Bolzplatzarena

Unterm Strich - lodash Performance

Vor einigen Monaten haben wir lodash für ein Projekt eingeführt und waren begeistert, welche Möglichkeiten es gibt komplexe Dinge umzusetzen. Allerdings sind wir bei einem bestimmten Teil der Projektes an den Punkt angekommen, dass es nicht immer auf Bequemlichkeit ankommt sondern auf Performance. Daher machten wir nach den Tests mit Moment.js auch Tests für bestimmtet Codestellen für lodash und waren zum Teil sehr schockiert. Da wir die Methoden häufig in Schleifen nutzen müssen, werden diese Methoden sehr häufig aufgerufen und so sind die Unterschiede von großer Bedeutung.

lodash reduce vs pure reduce

Fangen wir mir einem einfachen Beispiel an. Wir haben lodashs reduce mit pure recude verglichen. Die Aufrufe sind fast identisch.

reduce(array, (sum, n) => sum + n, 0);

und die JS Variante

array.reduce((sum, n) => sum + n, 0);

In diesem Beispiel bilden die Zeilen lediglich die Summe aller Elemente im Array.

Für meinen Test, habe ich 25000 Testeinträge generiert und das ganze 10.000 mal ausführen lassen, um etwas verständlichere Messwerte zu erlangen. Ich bilde nur die Summe um den Nebeneffekt von anderen Operationen niedrig zu haben. Zudem wurde auch der Test selbst mehrfach ausgeführt.

Das Ergebnis

Die Boardeigenen Mittel von JS schlagen lodash mit 183ms zu 255ms. Ich finde die Leserlichkeit gewinnt in diesem Falle nicht und daher würde ich bei diesem Szenario bei JS bleiben.

pullAllWith vs. pull mit find und includes

Machen wir es nun etwas komplizierter. Stellen wir uns vor, wir haben ein großes Array. Aus diesem Array sollen nun diverse Werte entfernt werden. Einfach gesprochen, ich möchte nur die Elemente aus dem ersten Array, welche im zweiten nicht drin sind.

Man könnte dies so schreiben

localArray = localArray.filter(item => !pullArray.includes(item));

Man könnte dies aber auch mit lodash schreiben

pullAllWith(localArray, pullArray, (a, b) => a === b);

In diesem Fall mutiert localArray und muss nicht nochmals zugewiesen werden. Das gefällt mitunter nicht jedem. Gerade wenn man die Eingabeparameter einer Methode eigentlich gar nicht ändern möchte oder man wirklich auch dieses Array braucht.

Ist dieses Verhalten egal kann die lodash Variante deutlich schneller sein. Ich schreibe kann, weil es von den Daten abhängt. Desto mehr Daten zu entfernen sind desto langsamer wir lodash. Das liegt daran, wie der Code strukturiert wird. Dort wird nämlich in der äußeren Schleife über das Array zum entfernen iteriert.

Das Ergebnis

In meinen Tests wurde der Code ohne lodash dann schneller, wenn mehr als 20% der Daten zu entfernen waren. Müsste man noch spreaden um das mutieren auszugleichen, läge der Wert noch deutlich darunter. Das bedeutet, desto größer die Quelle und desto kleiner die Menge der zu löschenden Daten desto eher sollte man zu lodash tendieren.

Geht das besser?

Ja. Uns zwar mit "some". Verwendet man statt includes some kann man bereits ab ca. 3% lodash schlagen. Dieser Fall deckt dann auch die Fälle ab, wenn man nicht nur einfach eine ID hat. Wenn man mühevoll auch zuvor gemapt hat, kann man auch darauf noch verzichten.