2012-04-02 15 views
8

array.forJeder läuft schneller als native Iteration? Wie?

Es war mein Verständnis, dass Testfall 2 langsamer als Testfall 1 laufen sollte - ich wollte sehen, wie viel langsamer. Stellen Sie sich meine Überraschung vor, wenn ich sehe, dass es schneller läuft!

Was geht hier vor? Optimierung hinter den Kulissen? Oder ist .für immer sauberer und schneller?

Testing in Chrome 18.0.1025.142 32-Bit-Windows Server 2008 R2/7 64-bit

+1

'forEach' hat wahrscheinlich einige native Optimierungen oder etwas. –

+3

Was mehr ist, erhalten Sie nicht einmal den Wert aus dem Array in Testfall 1, Sie loggen ich anstelle von 'Array [i] ' –

+0

1) Sie sollten das Array nicht bei jedem Test erstellen, die Sie definieren können vars, die bei allen Tests verfügbar sein werden 2) Sie überprüfen '.length' jede Schleife – ajax333221

Antwort

7

Es gibt viele Iteration Optimierungen sind, die Ihre for Schleife fehlt wie:

  • Cache das Array Länge
  • Iterierte rückwärts
  • Verwendung ++ Zähler anstelle des Zählers ++

Das sind die, von denen ich gehört und benutzt habe, ich bin mir sicher, dass es mehr gibt. Wenn der Speicher mir richtig dient, ist die rückwärts iterierende while-Schleife die schnellste aller Schleifenstrukturen (in den meisten Browsern).

Für einige Beispiele siehe this jsperf.

Bearbeiten: Links für postfix vs prefix perf test und iterating backwards. Ich konnte meine Referenz für die Verwendung von + = 1 anstelle von ++ nicht finden, daher habe ich sie aus der Liste entfernt.

+0

Ich habe gehört, dass für C, dass ++ ich schneller als i ++ ist, weiß nicht, ob das auch für Javascript –

+0

iteriert rückwärts gilt und die Verwendung von '+ = 1' statt' ++ 'ändert eigentlich nichts in JS. – kirilloid

+0

@kirilloid + = und ++ sind zwei völlig verschiedene Operatoren, die in verschiedenen Parser-Implementierungen mit unterschiedlichen Geschwindigkeiten laufen können, und Dekrementieren gegen Inkrementieren ist eine bekannte Mikrooptimierung. Ich werde bearbeiten, um Referenzen hinzuzufügen. – jbabey

0

Sie sind ungefähr gleich für mich in Opera. Zu beachten ist, dass Ihre Bedingung in for() array.length ist. Wenn Sie die Länge des Arrays in einer Variablen und dann in einer Schleife zwischenspeichern, sollten Sie eine bessere Leistung sehen.

1

Lesen length von array bei jeder Iteration möglicherweise langsam, aber forEach ist comomonly langsamer, weil Funktionsaufruf nicht billig Operation in js ist.

PS: forEach ist 14% langsamer auf FF10.

+0

Ich denke es ist immer noch wichtig, aber ich glaube, die JITs haben Funktionsaufrufe erheblich zippiger gemacht. –

+0

Ich auch =) Besonders danach beschleunigte ich CPU-schweren JS-Code ~ 5 mal mit nur Inlining-Funktionen. – kirilloid

+0

Egal was ich versuche, forEach ist in Chrome immer schneller. – trusktr

0

Vielleicht ist das for() langsamer, weil die Schleife 'array.length' auf jede Iteration anwendet, um die Länge des Arrays zu erhalten.

Versuchen:

var nri = array.length; 
for(var i = 0; i < nri; i++){ 
    // ... 
} 
3

UPDATE:

Viele der alten Tricks in diese Antworten sind für interpretiert JS in älteren Browsern.

In jeder modernen JS-Implementierung, einschließlich aller modernen Browser, Node und den neuesten mobilen Webansichten, können Inline-Funktionen tatsächlich vom JIT (JS-Compiler) zwischengespeichert werden, wodurch forEach typischerweise eine viel schnellere Option für Array-Iteration ist. Früher war das Gegenteil der Fall, wenn das wiederholte Aufrufen einer Funktion wiederholt einen Aufbau-/Abbauprozess erforderte, der die Leistung einer nicht-trivialen Schleife erheblich verringern könnte.

Für die beste Leistung würde ich vermeiden, auf etwas zu verweisen, das nicht als Argument übergeben oder in der Funktion selbst definiert wurde, wenn Sie nicht müssen. Ich bin mir nicht 100% sicher, dass das wichtig ist, aber ich konnte sehen, warum es möglich ist.

Getter-Werte, die jede Art von Lookup-Prozess wie Array-Längen oder DOM-Knoten-Eigenschaften beinhalten, werden wahrscheinlich auch noch am besten im Cache einer Variablen gespeichert.

Aber darüber hinaus würde ich versuchen, lassen Sie einfach das grundlegende Prinzip der Arbeitsvermeidung führen Sie Ihre perf Bemühungen. Die Vorberechnung von Dingen, die nicht in einer Schleife neu berechnet werden müssen, oder das Zwischenspeichern eines Abfrage-Selektor-Ergebnisses auf var, anstatt wiederholt im DOM zu stöbern, sind gute Beispiele dafür. Zu hart zu versuchen, das JIT-Verhalten zu nutzen, wird wahrscheinlich ziemlich geheimnisvoll werden und wahrscheinlich nicht im Laufe der Zeit oder über alle JITs hinweg bestehen.

ALTE ANTWORT:

Okay, Wand des Textes vergessen. Aufzählungszeichen:

var i = someArray.length; //length is cached 
someArray.reverse(); //include this only if iterating in 0-(length-1) order is important 

while(i--){ 
//run a test statement on someArray[i]; 
} 
  • Länge zwischengespeichert wird und unverzüglich in den Index

  • Der Vorteil rückwärts in JS AFAIK Iterieren ist ein logischer Operator mit zwei Operanden zu vermeiden. In diesem Fall bewerten wir nur eine Nummer. Es ist wahr oder es ist Null und falsch.

  • Ich finde es auch elegant.

Verwandte Themen