2012-04-02 18 views
8

http://jsperf.com/testing-foreach-vs-for-looparray.for Czy działasz szybciej niż natywna iteracja? W jaki sposób?

To było moje zrozumienie, że Test Case 2 powinien działać wolniej niż Test Case 1 - Chciałem zobaczyć, o ile wolniej. Wyobraźcie sobie moje zdziwienie, gdy widzę, że działa szybciej!

Co tu się dzieje? Za kulisami optymizacji? Lub jest. Dla każdego czyszczenia i szybsze?

Testowanie w Chrome 18.0.1025.142 32-bitowy Windows Server 2008 R2/7 64-bit

+1

'forEach' prawdopodobnie ma pewne natywne optymalizacje lub coś. –

+3

Co więcej, nie dostajesz nawet wartości z tablicy w Przypadku testowym 1, logujesz się i zamiast 'tablica [i]' –

+0

1) nie powinieneś tworzyć tablicy przy każdym teście, możesz zdefiniować vars, które będą dostępne we wszystkich testach 2) sprawdzasz '.length' w każdej pętli – ajax333221

Odpowiedz

7

Istnieje wiele optymalizacji iteracji pętli for że brakuje takich jak:

  • podręcznej tablicy długość
  • iteracji wstecznej
  • użycie ++ licznik zamiast licznik ++

Są to te, które słyszałem i używane, jestem pewien, że jest ich więcej. Jeśli pamięć służy mi poprawnie, wsteczna iteracja podczas pętli jest najszybszą ze wszystkich struktur pętli (w większości przeglądarek).

Zobacz kilka przykładów na temat this jsperf.

Edytuj: łączy dla postfix vs prefix perf test i iterating backwards. Nie mogłem znaleźć mojego odnośnika do używania + = 1 zamiast ++, więc usunąłem go z listy.

+0

Słyszałem, że dla C, że ++ i jest szybsze niż i ++, nie wiem, czy to również dotyczy Javascript –

+0

iteruje do tyłu, a użycie '+ = 1' zamiast' ++ 'faktycznie niczego nie zmienia w JS. – kirilloid

+0

@kirilloid + = i ++ to dwa zupełnie różne operatory, które mogą działać z różnymi prędkościami w różnych implementacjach analizatora składni, a dekrementacja w porównaniu z inkrementacją jest dobrze znaną mikro-optymalizacją. będę edytować, aby dodać odniesienia. – jbabey

0

Są mniej więcej takie same dla mnie w Operze. Coś wartego odnotowania jest to, że twoje warunkowe w for() jest array.length. Jeśli buforujesz długość tablicy w zmiennej, a następnie pętlę, powinieneś zobaczyć lepszą wydajność.

1

Odczytywanie length z w każdej iteracji może być powolne, ale forEach jest comomonly wolniej, ponieważ wywołanie funkcji nie jest tanią operacją w js.

PS: forEach jest 14% wolniejsza na FF10.

+0

Myślę, że nadal ma to znaczenie, ale uważam, że JIT sprawiły, że funkcje znacznie się zippier. –

+0

Ja też =) Zwłaszcza po tym, przyśpieszyłem procesorowy kod JS ~ 5 razy tylko z wbudowanymi funkcjami. – kirilloid

+0

Bez względu na to, co próbuję, forEach jest zawsze szybszy w Chrome. – trusktr

0

Być może parametr for() jest wolniejszy, ponieważ pętla stosuje "array.length" do każdej iteracji, aby uzyskać długość tablicy.

Spróbuj:

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

UPDATE:

Wiele starych sztuczek w tych odpowiedzi są idealne dla interpretowane JS w starszych przeglądarkach.

W każdej nowoczesnej implementacji JS, w tym we wszystkich nowoczesnych przeglądarkach, węźle i najnowszych odsłonach witryn mobilnych, funkcje wbudowane mogą być faktycznie buforowane przez JIT (kompilator JS), co czyni opcję znacznie szybszą dla iteracji macierzy. Kiedyś po prostu nawiązywanie połączeń z funkcją wielokrotnie wymagało procesu kompilacji/rozpadu, który mógłby znacznie obniżyć wydajność nietrywialnej pętli.

Aby uzyskać najlepszą wydajność, unikałbym odniesienia do wszystkiego, co nie zostało przekazane jako argument lub zdefiniowane w samej funkcji, jeśli nie musisz tego robić. Nie jestem w 100% pewien, że to ma znaczenie, ale mogłem zrozumieć, dlaczego tak się stało.

Wartości gettera, które obejmują dowolny proces wyszukiwania, taki jak długość macierzy lub właściwości węzła DOM, prawdopodobnie są nadal najlepiej buforowane do zmiennej.

Ale staram się po prostu pozwolić, by podstawowa zasada unikania pracy poprowadziła twoje perfekcyjne wysiłki. Wstępne obliczanie rzeczy, które nie muszą być ponownie obliczane w pętli lub buforowanie wyniku selektora zapytania do var, zamiast wielokrotnego grzebania w DOM, są tego dobrym przykładem. Próby zbyt dużego wysiłku, aby skorzystać z zachowania JIT, zapewne staną się bardzo tajemnicze i prawdopodobnie nie utrzymają się w czasie lub we wszystkich JIT.

OLD ODPOWIEDŹ:

Dobra, zapomnij ścianę tekstu. wypunktowania:

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]; 
} 
  • długość jest buforowane i natychmiast wprowadzone do indeksu

  • Zaletą iteracji wstecz w JS AFAIK jest unikanie operator logiczny z dwoma argumentami. W tym przypadku po prostu oceniamy liczbę. To prawda albo zero i fałsz.

  • Uważam też, że jest elegancka.

Powiązane problemy