2013-04-07 10 views
8

http://jsperf.com/loops/67Czy ktoś może wyjaśnić, w jaki sposób tej pętli udaje się porównywać tak wysoko?

Jeśli przyjrzeć się, co następuje pętla zarządza jakieś szalone odniesienia:

var i=0; 
var v; 
for (i, v; v = arr[i++];) { 
    v; 
} 

To słabo ~ 700 mln ops/s w FF, ~ 20 mil w Chrome, a ~ 50mil w IE10. Kolejna najszybsza pętla zarządza ~ 100k w FF, ~ 6k w IE10 i zaledwie ~ 2k w Chrome.

Dlaczego jest tak szybki? Widzę oczywiste różnice między innymi pętlami i to, jak jeden jest szybszy od drugiego, ale nie mogę wymyślić niczego, co tłumaczyłoby absolutnie niewiarygodną różnicę w wydajności z tą pętlą, 700 milionów do 100 000 to szalona luka.


Edit po odpowiedzi:

Opierając się odpowiedź @Michael Gary'ego, wróciłem i edytować konfigurację obejmować rzeczywisty prawdziwe tablicę, a wyniki spadły z powrotem do rzeczywistości: http://jsperf.com/loops/70

+3

Ponieważ nic nie robi, prawdopodobnie został zoptymalizowany jako taki przez tłumacza. – Brad

+0

Jakiś rodzaj [Optymalizacji pętli] (http://en.wikipedia.org/wiki/Loop_optimization) obecny w jednym i nieobecny w innych? – FRD

+0

w punkcie widzenia asemblera pętla robi tylko 3 rzeczy: przesuń wskaźnik tablicy o jeden krok w prawo, przetestuj nową wartość, przejdź do początku pętli. można to zrobić szybko. nie mam pojęcia o javascript. :( – scones

Odpowiedz

7

Powód jest prosty. Tablica arr tworzony jest z tym kodem:

var arr = new Array(10000); 

Więc to ma długość 10000, ale wszystkie elementy są undefined. Pętla ta nie działa przy długości tablicy, ale kończy się, gdy napotka „falsy” wartość - przy założeniu, że pętla zostanie zatrzymane, gdy v odbiera wartość undefined w wyniku próby odczytu poza końcem tablicy.

Ale w tej konkretnej macierzy, wszystkie dziesięć tysięcy elementy mają wartość undefined. Tak więc pętla zatrzymuje się, gdy testuje pierwszy element tablicy. Innymi słowy, nie zapętla się wcale! Nic dziwnego, że jest szybki.

Ale co z bardziej rzeczywistą sprawą? W jaki sposób tego rodzaju taryfy pętli z długim tablicy JSON obiektów:

[ 
    { "id": 507674, "name": "Kolink" }, 
    { "id": 997356, "name": "DarkLord7854" }, 
    { "id": 1202830, "name": "Michael Geary" }, 
    /* and thousands more */ 
] 

Tutaj nie ma problemu pętli kończącej natychmiast, ponieważ wszystkie elementy tablicy są „truthy”.

W nowoczesnych silnikach JavaScript ta okazuje się być dość ubogi sposób napisać pętlę, bo niedawno dowiedziałem się do mojego skrajnego zakłopotania.

Byłem jednym z autorów jQuery Cookbook: Napisałem większość z Rozdziału 5, "Szybciej, Prostiej, Więcej Zabawy". Cóż, "szybsza" część nie wypadła tak dobrze.Byłem polecając pętlę bardzo dużo jak twoje do iteracji na dużej tablicy obiektów, takich jak ten powyżej:

for(var item, i = -1; item = array[++i];) { 
    // do stuff with item 
} 

Okazuje się, że w nowoczesnych przeglądarkach, to trochę wolniej niż konwencjonalnej pętli takiego:

for(var i = 0, n = array.length; i < n; i++) { 
    var item = array[i]; 
    // do stuff with item 
} 

Część to ze względu na fakt, że próbuje odczytać poza końcem tablicy rzuca pewne silniki JavaScript powrotem do deoptimized drodze reprezentujący tablicę, jako jeden z autorów V8 wyjaśnił mi na Google I/O w zeszłym roku. Część tego może być spowodowana przeglądarkami optymalizującymi bardziej powszechne rodzaje pętli i nie optymalizującymi tego mniej powszechnego podejścia.

Albo drogą, pętla bardziej konwencjonalny okazuje się szybciej w nowoczesnych przeglądarek:

http://jsperf.com/mikes-loops/2

Ale to już zupełnie inna sprawa z pętli. W twoim, szalony wzrost wydajności wynika bezpośrednio z faktu, że nie uruchamia on pętli w ogóle. :-)

+1

I to jest to, co dostaję za spóźnienie się i nie przeczytanie tego, co test został ustawiony do zrobienia .. hah. Dziękuję za odpowiedź, ale teraz mogę iść spać z moim mózgiem na luzie – Enzo

+1

Wróciłem i zmieniłem ustawienia, aby mieć poprawną tablicę, i masz całkowitą rację: http://jsperf.com/loops/70 – Enzo

3

arr jest inicjalizowany do tablicy zawierającej 10000 wielu błędów. Array(10000) przygotowuje długość tablicy, ale nie wypełnia jej w żaden sposób.

Dlatego arr[0] będzie undefined, który jest falsy, więc pętla for kończy się natychmiast.

Zasadniczo kod sprowadza się zrobić:

var i=0; 
var v; 
i,v; // doesn't do anything but access the variables 
v = undefined; 
i++; 
+4

'undefined' zamiast 'null'a – scones

Powiązane problemy