Rolf B: Replikation von Method Chaining außerhalb von Objekten?

Beitrag lesen

Hallo Christian,

effizient? NEIN, das ist es nicht. Ich habe ein paar Messungen gemacht.

Das ist die Basismessung (Nullpunkt), die braucht bei mir 17ms.

const t0 = performance.now();
let total = 0;

for (let i = 0; i<10000000; i++) {
   let result = (i%10);
   tot += result;
}
const t1 = performance.now();

Das ist die handgemachte Funktionskette, die braucht 3ms länger. Oder 0.3ns pro Aufruf von ams. Hui.

function add1(x) { return x+1; }
function mul2(x) { return x*2; }
function sub7(x) { return x-7; }

const t0 = performance.now();
let total = 0;

let ams = x => sub7(mul2(add1(x)));

for (let i = 0; i<10000000; i++) {
   let result = ams(i%10);
   tot += result;
}
const t1 = performance.now();

Nun der Vorschlag von 1unitedpower. Ich schreibe die eigentlich Messschleife jetzt nicht mehr ab.

let ams = reduceChain(add1, mul2, sub7);

function reduceChain(...fs) {
   return x0 => fs.reduce((x,f) => f(x), x0);
}

Die Laufzeiten der Messschleife liegen nun im Bereich von 360ms. Also 36ns pro Aufruf statt 0,3. Das ist Faktor 100.

Es ist natürlich immer noch schnell. Und im Normalfall wird man es nicht merken.

Aber es geht besser. Ich habe einen Chainer geschrieben, der das Verhalten der handgemachten Kette nachbaut:

function turboChain(...fs) {
      let f = "x0";
      for (let i=0; i<fs.length; i++)
         f = "fs[" + i + "](" + f + ")";
      return eval("x0 => " + f);
}

Ich baue eine Aufrufkette als String zusammen und compiliere den mit eval in eine Javascript-Funktion. Laufzeit: 0,8ns pro Aufruf. 💨

Ist das nun evil eval? Ich finde nicht - der evaluierte Code ist strikt kontrolliert und ich wüsste nicht, wie man sonst in diese Geschwindkeitsklasse kommen kann. Denn der Zeitfresser ist das Zwischenspeichern der Ergebnisse.

function ams(x0) {
   let result = add1(x0);
   result = mul2(result);
   return sub7(result);
}

landet nämlich ebenfalls in der 30ns Liga.

Der Aufwand mit eval lohnt aber nur, wenn man die verkettete Funktion wiederverwendet. Für einen einzelnen Aufruf lohnt das nicht. Und für 1000 auch nicht - wen interessiert bei einer Onlineanwendung 1ms Laufzeitunterschied? In einem Action-Spiel wird es aber wieder spannend.

Rolf

--
sumpsi - posui - obstruxi