$ .each () vs for () Schleife - und Leistung

75

Dies sind hauptsächlich nur einige Dinge, die ich mich gefragt habe. Vielleicht kann mir jemand ein bisschen mehr Einblick in sie geben. Ich werde auch mitteilen, was mir bisher aufgefallen ist!

Das erste, was ich mich gefragt habe ... gibt es einen guten oder guten Grund für die Verwendung:

$('element').each(function (i, el) { });

-- gegen --

$.each($('element'), function (i, el) { });

Wenn ich mir die jQuery-Dokumente ansehe, sehe ich keinen Reim oder Grund für den einen oder anderen (vielleicht kennen Sie eine Instanz oder zusätzliche Dinge, die man über die andere tun kann.

Aber noch wichtiger ist ich mit betroffenen Geschwindigkeit hier

// As opposed to $.each() looping through a jQuery object
// -- 8x faster 
for (var i = 0, $('.whatever').length; i < len; i++) {
    $('.whatever')[i] // do stuff
}

Wenn Sie diese Besuche jsFiddle DEMO hier , werden Sie den Unterschied in der Geschwindigkeit sehen mit einer von ihnen im Grunde gleichwertig ist, aber noch wichtiger Ich fühle mich wie ich sollte immer werden mit for()Schleifen ...

Ich habe nur Unit-Tests durchgeführt (50.000 Mal jede der 5 verschiedenen Szenariofunktionen durchlaufen), einfach eine Reihe von Listenelementen durchlaufen und a festgelegt data-newAttr, nichts Besonderes.


FRAGE :: Ich denke, meine größte Frage ist, warum nicht immer for-Schleifen verwenden, während ich durch ein Objekt iteriere. Gibt es überhaupt einen Grund, $ .each () zu verwenden? Verwenden Sie immer for () -Schleifen, auch wenn Sie jQuery-Objekte durchlaufen?

jsFiddle DEMO hier

Function type:                  Execution Time:
_testArea.each() + $(this)               1947   <-- using $(this) slows it down tremendously
$.each()         + $(this)               1940
_testArea.each() + el(plain JS)           458   <-- using the Element speeds things up
$.each()         + el(plain JS)           452
for() loop       + plainJS[0] iteration   236   <-- over 8x faster

Nur meine 2 Cent. :) :)

Mark Pieszak - Trilon.io
quelle
31
Wie Joe Armstrong einmal als Antwort auf eine ähnliche Frage auf der Erlang-Mailingliste schrieb: "Schreiben Sie einfach das schönste Programm, das Sie können." Lassen Sie Leistungsprobleme zu Ihnen kommen. Arbeiten Sie wirklich an Seiten, die 50.000 Mal wiederholt werden? Wenn ja, dann auf jeden Fall optimieren.
Pointy
3
Wie würde eine forSchleife aussehen, die über jQuery DOM-Elemente iteriert?
Jordanien
2
Testen Sie es selbst auf jsperf.com
j08691
1
Javascript-Funktionen sind immer schneller als eine Jquery-Funktion, da Javascript nativ ist, aber ich denke, dass der Punkt, an dem die einzelnen statt für verwendet werden, den Code mithilfe des Frameworks und der Vorteile schneller macht
Jorge
5
Die .each()Methode iteriert über jQuery-Objekte. Die $.each()statische Methode kann verschiedene Arten von Objekten durchlaufen, z. B. einfache Objekte, Arrays und Array-ähnliche Objekte. Das ist der Unterschied.
Šime Vidas

Antworten:

47

Eine Sache, die .each()es Ihnen ermöglicht, dies nicht mit einer forSchleife zu tun, ist die Verkettung .

$('.rows').each(function(i, el) {
    // do something with ALL the rows
}).filter('.even').each(function(i, el) {
    // do something with the even rows
});

Ich habe mit Ihrer JSFiddle herumgespielt, um zu sehen, wie sich die Verkettung auf die Leistung auswirkt , wenn Sie Teilmengen der ursprünglichen Gruppe übereinstimmender Elemente durchlaufen müssen.

Das Ergebnis war nicht allzu unerwartet, obwohl ich denke, dass der Overhead von end()hier aufgrund der Kombination von wenigen Elementen und vielen Schleifen übertrieben war. Davon abgesehen: Einfache JS-Schleifen sind immer noch etwas schneller, aber ob dies die zusätzliche Lesbarkeit .each()(und Verkettung) beeinträchtigt, ist umstritten.

Peter-Paul van Gemerden
quelle
Beeindruckend! Danke, ich habe nicht einmal darüber nachgedacht, so zu verketten, das ist definitiv ein großer Vorteil! Es ist so viel mehr Code in einfachem JS zu tun, und sobald Sie eine Reihe von if / else-Dingen haben, die das Gleiche bewirken, ist der ms-Vorteil so gut wie nicht vorhanden.
Mark Pieszak - Trilon.io
1
unperformant! Ich würde innerhalb des äußeren jedes () filtern, nur weil jedes (). Filter () dasselbe Array zweimal verarbeiten würde, es ist weniger praktisch, aber leistungsfähiger. Und wenn Sie eine große Anzahl von Elementen erwarten, würde ich auf jede () Iteration verzichten. Schauen Sie sich einfach jsperf.com/function-call-overhead-test bezüglich des Overheads von Funktionsaufrufen an
comeGetSome
22

Eine Sache, mit der Sie arbeiten, .each()ist das automatische lokale Scoping (da Sie für jedes Objekt eine anonyme Funktion aufrufen). Wenn Sie also bei jeder Iteration noch mehr anonyme Funktionen / Abschlüsse / Ereignishandler / was auch immer erstellen, müssen Sie dies niemals tun Sorgen Sie sich, dass Ihre Handler eine Variable gemeinsam nutzen. Das heißt, JavaScript verhält sich in Bezug auf lokale Bereiche nicht wie andere Sprachen, aber da Sie eine Variable überall deklarieren können, kann es Sie manchmal täuschen.

Mit anderen Worten, das ist falsch:

var idx,el;
for (idx = 0; idx <someObjectArray.length; idx++){
   el = someObjectArray[idx]
   el.someEventHandler(function(){  
       alert( "this is element " + idx);
   }); 
}

Immer wenn eines dieser Objekte nach dieser Schleife sein "someEvent" aufruft (bitte beachten Sie, dass dies erfunden ist), wird in der Warnung immer angegeben, was zuletzt zugewiesen wurde idx, was sein sollte (zum Zeitpunkt des Aufrufs) someObjectArray.length.

Um sicherzustellen, dass Sie den richtigen Index speichern, müssen Sie einen lokalen Bereich deklarieren, eine Variable erstellen und dieser Variablen zur Verwendung zuweisen.

var idx,el;
for (idx = 0; idx <someObjectArray.length; idx++){
   el = someObjectArray[idx];
   (function(){
       var localidx = idx;
       el.someEventHandler(function(){  
           alert( "this is element " + localidx);
       }); 
   })();
}

Wie Sie sehen können, ist das höllisch hässlich, aber es sollte funktionieren. Jeder Ereignishandler erhält eine eigene Kopie vonlocalidx

Vergleichen Sie das jetzt mit .each()

$(someObjectArray).each(function (idx, el) { 
   el.someEventHandler(function(){  
       alert( "this is element " + idx);
   }); 
});

Viel einfacher, nicht wahr?

JayC
quelle
1
Sehr richtig! Ich habe tatsächlich für eine Sekunde vergessen, dass es dies bereits für Sie erledigt ... Ich nehme an, das Größte, was Sie daraus ziehen können, ist, dass Sie eine einfache Manipulation wünschen get / set type things a easy für () w plain JS ist wirklich der richtige Weg. Für viel kompliziertere Filter- und EventHandler benötigen Sie fast jeden (). Interessant ...
Mark Pieszak - Trilon.io
9

jQuery.each vs for-Schleife

Vorteile jQuery.each:

  • Passt gut in jQuery-Code (Verkettung und Stil).
  • Keine Sorge um den Umfang (Verweise auf den Iterator und das Objekt bleiben bestehen).
  • Kann universell verwendet werden (für alle Arten von Objekten und Iteration über Objektschlüssel).

Vorteile for-Schleife:

  • Hohe Leistung (für Spiele / Animationen / große Datenmengen).
  • Volle Kontrolle über den Iterator (Elemente überspringen, Elemente aus der Liste verbinden usw.).
  • Die for-Schleife funktioniert immer, da keine Abhängigkeit von jQuery besteht.
  • Gleiche bekannte Syntax wie die meisten anderen ähnlichen Sprachen.

Beispielcode

Dies ist ein Beispielcode dafür, wie ich eine Liste lieber iteriere.

var list = ['a', 'b', 'c', 'd', 'e', 'f'];

jQuery.each:

$.each(list, function(i, v)
{
    // code...
});

For-Loop ohne Verschluss:

for(var i=0,v,n=list.length;i<n;i+=1)
{
    v = list[i];
    // code...
}

For-Loop mit Verschluss:

for(var i=0,n=list.length;i<n;i+=1)
{
    (function(i, v)
    {
        // code...
    })(i, list[i]);
}

Hinweis: Ich schlage vor, dass Sie nur die Standard-for-Schleife verwenden und nur bei Bedarf einen Verschluss verwenden. Wenn Ihr Code jedoch sowieso eher wie jQuery als wie Javascript aussieht, ist es möglicherweise einfacher, ihn nur zu verwenden $.each. Bei Leistungsproblemen können Sie diese jederzeit nachprüfen.

Yeti
quelle
5

Ich habe vor einiger Zeit einen einfachen Leistungstest durchgeführt: http://jsperf.com/forloops3 . Scheint, dass das Festhalten an einfach, alt for loop(wo es möglich ist) der richtige Weg ist :)

op1ekun
quelle
4

Als ich zu Ihrem Link ging, habe ich zwei Zahlen:

$.each() + el(plain JS) 401
for() loop + plainJS[0] iteration   377

Wenn der Unterschied so gering ist, wählen Sie den am besten lesbaren. Wenn Sie jedoch einen sehr hohen Zeitbedarf haben, müssen Sie möglicherweise nur den schnellsten wählen.

Ich würde vorschlagen, dass Sie Ihr Programm so schreiben, dass drei verschiedene Methoden verwendet werden, die beiden oben genannten, und dann das foreach verwenden, das in neueren Versionen von Javascript enthalten ist. Für Browser, die es nicht unterstützen, können Sie es als Prototyp hinzufügen.

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach

Sie wissen, was Ihre Anforderungen sind und was Ihr Programm tun wird. Schreiben Sie einfach Ihre eigenen Tests und stellen Sie sicher, dass es den Anforderungen der von Ihnen unterstützten Browser entspricht.

Bei Ihrer ersten Frage würde ich mitmachen, $('element').eachda es viel einfacher zu lesen ist, aber das ist nur meine Meinung.

James Black
quelle
2
Obwohl es für so kleine Ränder wahrscheinlich keinen Unterschied macht . Ich würde nur die "klarere konsistente Version" (je nachdem, was bestimmt ist) verwenden, es sei denn, es gab eine bestimmte reale Leistung Fall zeigt an, dass es zu langsam war.
1
@pst - Der kleine Rand kann einen Unterschied machen, wenn Sie ihn 10000 Mal aufrufen. Dieser kleine Unterschied bringt Sie außerhalb Ihres zulässigen Fensters, worüber ich gefragt habe. Der einzige Weg, dies wirklich zu wissen, besteht darin, in verschiedenen Browsern mit dem zu testen drei Versionen und einige Zahlen bekommen.
James Black
Danke James! Ja, in meinem Fall ist es definitiv ein Problem, wir müssen ältere Browser unterstützen, aber jetzt sehe ich, dass Lesbarkeit und Verkettbarkeit - weise - sinnvoll sind, zu verwenden each()und danach bei einfachem JS zu bleiben! Der Unterschied ist wirklich nicht vorhanden. Es scheint, dass ich ihn nicht verwenden muss, es sei denn, ich brauche ihn, um ein JS-Objekt zu bleiben $(this).
Mark Pieszak - Trilon.io
2

Tatsächlich gibt es einen großen Unterschied zwischen $ .each () und $ (). Each ().

Sie machen etwas andere Dinge, je nachdem, was Sie übergeben.

http://api.jquery.com/each/ vs http://api.jquery.com/jquery.each/

jquery.each ist ein generischer Iterator, wobei $ (). each () spezifisch für eine jquery-Sammlung ist.

Siehe auch: http://jsperf.com/each-vs-each-vs-for-in/9

Ryanneufeld
quelle
Sie können beide genauso einfach auf die gleiche Weise verwenden: $(['someItem', 'anotherItem']).each(function (i, el) { }); jsfiddle.net/zzVQD . Dies bedeutet auch nicht, dass die Frage eine Ablehnung verdient. Ich habe viel Forschung / Code / Aufwand investiert.
Mark Pieszak - Trilon.io
1
Obwohl dies keine Antwort auf diese Frage ist, fügt es etwas Wissen hinzu.
Swaps