Ich habe versucht, den schnellsten Weg zu finden, um eine for-Schleife mit einem eigenen Bereich auszuführen. Die drei Methoden, die ich verglichen habe, waren:
var a = "t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t".split();
// lodash .each -> 1,294,971 ops/sec
lodash.each(a, function(item) { cb(item); });
// native .forEach -> 398,167 ops/sec
a.forEach(function(item) { cb(item); });
// native for -> 1,140,382 ops/sec
var lambda = function(item) { cb(item); };
for (var ix = 0, len = a.length; ix < len; ix++) {
lambda(a[ix]);
}
Dies ist unter Chrome 29 unter OS X. Sie können die Tests hier selbst ausführen:
Wie ist Lodash .each
fast doppelt so schnell wie einheimisch .forEach
? Und außerdem, wie ist es schneller als die Ebene for
? Zauberei? Schwarze Magie?
javascript
performance
lodash
Matt Zukowski
quelle
quelle
lambda
Ding? Warum setzen Sie nicht einfachcb
direkt?.each()
ist für mich viel langsamer als jede andere Methode in Ihrem Test.FF 23.0.1
.each()
undfor
ergibt sich aus der zusätzlichen Funktionssuche (lambda
). Eine aussagekräftigere Benchmark finden Sie unter jsperf.com/lo-dash-each-vs-native-foreach/15 .Antworten:
_.each()
ist nicht vollständig kompatibel mit[].forEach()
. Siehe folgendes Beispiel:var a = ['a0']; a[3] = 'a3'; _.each(a, console.log); // runs 4 times a.forEach(console.log); // runs twice -- that's just how [].forEach() is specified
http://jsfiddle.net/BhrT3/
Bei der Implementierung von lodash fehlt daher eine
if (... in ...)
Überprüfung, die den Leistungsunterschied erklären könnte.Wie in den obigen Kommentaren erwähnt, wird der Unterschied zu native
for
hauptsächlich durch die zusätzliche Funktionssuche in Ihrem Test verursacht. Verwenden Sie diese Version, um genauere Ergebnisse zu erhalten:for (var ix = 0, len = a.length; ix < len; ix++) { cb(a[ix]); }
http://jsperf.com/lo-dash-each-vs-native-foreach/15
quelle
for
ohne Verschluss nicht ganz gleichwertig ist. Das Innere desfor
Blocks erhält keinen eigenen Bereich.for (...) {(function(item) {cb(item);})(a[ix]);}
ist in dieser Hinsicht in Ordnung. Im Gegensatz zu Ihrem obigen Kommentar verursacht dies nicht für jede Iteration einen erheblichen Overhead. Siehe auchundefined
in einem Array wie[null, undefined, false]
ein Loch behandelt und überspringt, während andere dies nicht tun.jsperf
Link.http://kitcambridge.be/blog/say-hello-to-lo-dash/
Die Lo-Dash-Entwickler erklären (hier und in einem Video), dass die relative Geschwindigkeit des Native
forEach
zwischen den Browsern variiert. Nur weilforEach
es nativ ist, heißt das nicht, dass es schneller ist als eine einfache Schleife, die mitfor
oder erstellt wurdewhile
. Zum einenforEach
muss sich der mit mehr Sonderfällen befassen. ZweitensforEach
werden Rückrufe mit dem (potenziellen) Overhead des Funktionsaufrufs usw. verwendet.chrome
Insbesondere ist bekannt (zumindest den Lo-Dash-Entwicklern), dass sie relativ langsam sindforEach
. Für diesen Browser verwendet lo-dash eine eigene einfachewhile
Schleife, um an Geschwindigkeit zu gewinnen. Daher der Geschwindigkeitsvorteil, den Sie sehen (andere jedoch nicht).quelle
Ja, lodash / Unterstrich haben nicht einmal die gleiche Semantik wie
.forEach
. Es gibt ein subtiles Detail, das die Funktion sehr langsam macht, es sei denn, die Engine kann ohne Getter schnell nach spärlichen Arrays suchen.Dies ist zu 99% spezifikationskonform und läuft mit der gleichen Geschwindigkeit wie lodash in V8 für den allgemeinen Fall:
function FastAlmostSpecForEach( fn, ctx ) { "use strict"; if( arguments.length > 1 ) return slowCaseForEach(); if( typeof this !== "object" ) return slowCaseForEach(); if( this === null ) throw new Error("this is null or not defined"); if( typeof fn !== "function" ) throw new Error("is not a function"); var len = this.length; if( ( len >>> 0 ) !== len ) return slowCaseForEach(); for( var i = 0; i < len; ++i ) { var item = this[i]; //Semantics are not exactly the same, //Fully spec compliant will not invoke getters //but this will.. however that is an insane edge case if( item === void 0 && !(i in this) ) { continue; } fn( item, i, this ); } } Array.prototype.fastSpecForEach = FastAlmostSpecForEach;
Indem wir zuerst nach undefiniert suchen, bestrafen wir normale Arrays in der Schleife überhaupt nicht. Eine Engine könnte ihre Interna verwenden, um seltsame Arrays zu erkennen, V8 jedoch nicht.
quelle
Hier ist ein aktualisierter Link (ca. 2015), der den Leistungsunterschied zeigt, der alle drei vergleicht
for(...)
,Array.forEach
und_.each
: https://jsperf.com/native-vs-underscore-vs-lodashHinweis: Geben Sie hier ein, da ich noch nicht genügend Punkte hatte, um die akzeptierte Antwort zu kommentieren.
quelle
lodash.each
nicht mehr schneller zu sein alsforEach
(Chrome 78, 2020)