Jaki jest najszybszy sposób na przeglądanie tablicy w JavaScript?

249

Nauczyłem się z książek, które powinieneś pisać dla pętli w ten sposób :

for(var i=0, len=arr.length; i < len; i++){
    // blah blah
}

więc arr.lengthnie będzie to obliczane za każdym razem.

Inni twierdzą, że kompilator dokona optymalizacji, więc możesz po prostu napisać:

for(var i=0; i < arr.length; i++){
    // blah blah
}

Chcę tylko wiedzieć, który jest najlepszy sposób w praktyce?

wong2
źródło
1
warto również zajrzeć przy zapętlaniu tablic: jsperf.com/array-loop-var-caching
cloakedninjas
@ wong2 Ten test porównawczy od Browserdiet ma bardziej kompletny zbiór alternatyw.
Domi
1
jsben.ch/#/y3SpC
EscapeNetscape
Poprawiono w poprzednim jsben: jsben.ch/#/R6LbS
Corbfon
Czy możemy wprowadzić for ... ofpętlę do tego konkursu? Składnia wydaje się jeszcze łatwiejsza niż pętla for bez buforowania i chcę wiedzieć, czy powinienem przejść na używanie pętli for.
programista

Odpowiedzi:

339

Po wykonaniu tego testu w większości nowoczesnych przeglądarek ...

http://jsben.ch/dyM52

Obecnie najszybsza forma pętli (i moim zdaniem najbardziej syntaktycznie oczywista).

standard pętli z buforowaniem długości

for (var i = 0, len = myArray.length; i < len; i++) {

}

Powiedziałbym, że to zdecydowanie przypadek, w którym pochwalam programistów silnika JavaScript. Czas pracy powinien być zoptymalizowany dla jasności , a nie sprytu .

jondavidjohn
źródło
6
Co ciekawe, w IE9 jest to szybsze: dla (var i = 0, len = myArray.length; i <len; ++ i) {} // prefiks incr, zamiast postfiksa
Christopher Bennage
4
Zobacz Preferuj operatorów prefiksów nad postfiksami z innych powodów, aby ich używać ++i.
Bennett McElwee
4
Testowałem przy użyciu operatora prefiksu, jak sugerował @BennettMcElwee, i działa on trochę szybciej: for(var i=0, len=myArray.length; i<len; ++i) sprawdź jsperf.com/caching-array-length/84
victmo
21
Musisz być ostrożny używając tej pętli. Zacząłem go używać i miałem trudny do wyśledzenia błąd z powodu jednego błędu, który popełniłem. Jeśli zagnieżdżycie dwie takie pętle: jsfiddle.net/KQwmL/1 . Musisz zachować ostrożność, aby nazwać zmienną w dwóch pętlach inaczej, w przeciwnym razie druga pętla zastąpi pierwszą zmienną.
Rui Marques
6
@WillshawMedia Możesz zadeklarować wiele zmiennych za pomocą jednej varinstrukcji. Sposób, w jaki jest napisany, lenzależy od tego, jak sugerujesz.
jondavidjohn,
90

Absolutnie najszybszym sposobem na przejście przez tablicę javascript jest:

var len = arr.length;
while (len--) {
    // blah blah
}

Zobacz pełne porównanie na http://blogs.oracle.com/greimer/entry/best_way_to_code_a

gnur
źródło
1
Nie zapomnij użyć var(inaczej lenstaje się zmienną globalną). Zobacz także jsperf.com/loops, aby uzyskać więcej testów porównawczych pętli.
Mathias Bynens
22
Post na blogu, na którym oparta jest ta odpowiedź, ma już prawie 4 lata, a w tym czasie wiele się zmieniło w silnikach js, zaktualizowane porównanie znajduje się w mojej odpowiedzi poniżej.
jondavidjohn
1
Zgadzam się z @jondavidjohn. Przetestowałem ten kod i okazało się, że jest mniej wydajny ... Sprawdź jsperf.com/caching-array-length/84
victmo
Powyższa odpowiedź jest prawie powszechnie (w różnych przeglądarkach) znacznie wolniejsza niż w przypadku pętli for. Zobacz link JSPerf w zaakceptowanej odpowiedzi. To wielka szkoda, bo to wyjątkowo czytelna IMO.
Letharion
3
Zgaduję @jondavidjohn, że to, co rozumiesz przez „moja odpowiedź poniżej”, to „moja odpowiedź powyżej” lol.
Shanimal,
40

Począwszy od czerwca 2016 r. , Przeprowadzając niektóre testy w najnowszym Chrome (71% rynku przeglądarek w maju 2016 r. I stale rośnie):

  • Najszybsza pętla to pętla „for” , zarówno z buforowaniem, jak i bez buforowania, co zapewnia naprawdę podobną wydajność. (Pętla for z buforowaną długością czasami dawała lepsze wyniki niż ta bez buforowania, ale różnica jest prawie znikoma, co oznacza, że ​​silnik może być już zoptymalizowany, aby faworyzować standard i prawdopodobnie najprostszy dla pętli bez buforowania).
  • Pętla while ze spadkami była około 1,5 razy wolniejsza niż pętla for.
  • Pętla korzystająca z funkcji zwrotnej (podobnie jak standardowa forEach) była około 10 razy wolniejsza niż pętla for.

Wierzę, że ten wątek jest za stary i programiści wprowadzają w błąd, myśląc, że muszą buforować długość lub używać odwrotnych przejść z dekrementami w celu uzyskania lepszej wydajności, pisząc kod, który jest mniej czytelny i bardziej podatny na błędy niż prosta prosta pętla for. Dlatego polecam:

  • Jeśli aplikacja iteruje wiele elementów lub kod pętli znajduje się w często używanej funkcji, bezpośrednią odpowiedzią dla pętli jest odpowiedź:

    for (var i = 0; i < arr.length; i++) {
      // Do stuff with arr[i] or i
    }
  • Jeśli twoja aplikacja tak naprawdę nie wykonuje iteracji przez wiele elementów lub po prostu musisz wykonywać małe iteracje tu i tam, użycie standardowego wywołania zwrotnego forEach lub dowolnej podobnej funkcji z wybranej biblioteki JS może być bardziej zrozumiałe i mniej podatne na błędy, ponieważ zakres zmiennej indeksu jest zamknięty i nie trzeba używać nawiasów, uzyskując bezpośredni dostęp do wartości tablicy:

    arr.forEach(function(value, index) {
      // Do stuff with value or index
    });
  • Jeśli naprawdę potrzebujesz zarysować kilka milisekund podczas iteracji ponad miliardów wierszy, a długość tablicy nie zmienia się w trakcie procesu, możesz rozważyć buforowanie długości w pętli for. Chociaż myślę, że obecnie nie jest to naprawdę konieczne:

    for (var i = 0, len = arr.length; i < len; i++) {
      // Do stuff with arr[i]
    }
CGodo
źródło
Nie. jsbench.github.io/#67b13d4e78cdd0d7a7346410d5becf12 pokazuje, że najszybsze jest „Odwrotna pętla, niejawne porównanie, wbudowany kod” (105 221 operacji / s), podczas gdy „Pętla, wartość z pamięci podręcznej, wstawiony kod” uzyskały jedynie 76 635 operacji / s (Chrome 38,0.2125.111 )
Fr0sT
@ Fr0sT Twój test porównawczy jest innym scenariuszem, przemierzając tablice od indeksu 1 do <= długość. Oczywiście doprowadzi to do różnych wyników. Jeśli spróbujesz przemierzać tablice zerowe o długości <- co wydaje mi się, że jest to zwykły scenariusz - odkryjesz, że wyniki są lepiej optymalizowane za pomocą normalnej pętli „za” (przy czym buforowana długość jest nieco szybsza).
CGodo
Kyopaxa zmienił testy porównawcze na (0 <= i <długość), wyniki są takie same. „Odwrócona pętla, niejawne porównanie, wywołanie funkcji” uzyskała 365 kop / s, natomiast „Pętla, wartość w pamięci podręcznej, kod wstawiony” uzyskała 350 kop / s (FF 51)
Fr0sT
@ Fr0sT, jeśli zmienisz buforowane pętle for bez zerowania, bez równego porównania, na przykład for(let i=0, j=array.length; i < j; i++)znacznie przyspieszysz przesyłanie do przodu dla pętli. W kilku testach przeprowadziłem, że wygrał, w większości mieścił się w granicach błędu lub pętli zwrotnej.
Izaak B
1
@IsaacB i tak dalej, przepraszam, nie zauważyłem, że ławka jest całkiem niepoprawna - wszystkie bezpośrednie pętle iterują 1.. długość, podczas gdy pętle odwrotne iterują długość..0 (pozycja arr [długość] jest nieprawidłowa). Poprawiłem testy i teraz pokazują one następujące wyniki: „Pętla, kod wstawiony” 360,616 operacji / sek ± 0,27%, „Pętla, wartość buforowana, kod wstawiony” 345,786 operacji / sek ± 2,18% (Sic!) ”Pętla zwrotna, niejawne porównanie, wstawiony kod „322.640 operacji / s ± 2,90% (!!!). Testy zostały wykonane przez FF51. Nowa ławka jest tutaj jsbench.github.io/#6bdfcd2692ba80c16a68c88554281570 . Wydaje się więc, że nie ma sensu ulepszać pętli.
Fr0sT
31

Jeśli zamówienie nie jest ważne, wolę ten styl:

for(var i = array.length; i--; )

Buforuje długość i jest znacznie krótszy do napisania. Ale będzie iterować po tablicy w odwrotnej kolejności.

Felix Kling
źródło
6
Właśnie to zabiłeś.
Vignesh Raja,
nie potrzebujesz i> = 0 ;?
MarwaAhmad
3
@MarwaAhmad: Nie. i--Zwraca liczbę, a gdy liczba jest 0warunkiem, to falsedlatego, że Boolean(0) === false.
Felix Kling
31

To tylko 2018, więc aktualizacja może być przyjemna ...

I naprawdę muszę się nie zgodzić z przyjętą odpowiedzią . Odracza się w różnych przeglądarkach. niektóre robią forEachszybciej, niektóre for-loop, a niektóre while są testem porównawczym dla wszystkich metod http://jsben.ch/mW36e

arr.forEach( a => {
  // ...
}

a ponieważ można zobaczyć wiele for-loop, for(a = 0; ... )warto wtedy wspomnieć, że bez zmiennych zmienne będą definiowane globalnie, co może dramatycznie wpłynąć na szybkość, więc będzie wolniej.

Urządzenie Duffa działa szybciej w operze, ale nie w Firefoxie

var arr = arr = new Array(11111111).fill(255);
var benches =     
[ [ "empty", () => {
  for(var a = 0, l = arr.length; a < l; a++);
}]
, ["for-loop", () => {
  for(var a = 0, l = arr.length; a < l; ++a)
    var b = arr[a] + 1;
}]
, ["for-loop++", () => {
  for(var a = 0, l = arr.length; a < l; a++)
    var b = arr[a] + 1;
}]
, ["for-loop - arr.length", () => {
  for(var a = 0; a < arr.length; ++a )
    var b = arr[a] + 1;
}]
, ["reverse for-loop", () => {
  for(var a = arr.length - 1; a >= 0; --a )
    var b = arr[a] + 1;
}]
,["while-loop", () => {
  var a = 0, l = arr.length;
  while( a < l ) {
    var b = arr[a] + 1;
    ++a;
  }
}]
, ["reverse-do-while-loop", () => {
  var a = arr.length - 1; // CAREFUL
  do {
    var b = arr[a] + 1;
  } while(a--);   
}]
, ["forEach", () => {
  arr.forEach( a => {
    var b = a + 1;
  });
}]
, ["for const..in (only 3.3%)", () => {
  var ar = arr.slice(0,arr.length/33);
  for( const a in ar ) {
    var b = a + 1;
  }
}]
, ["for let..in (only 3.3%)", () => {
  var ar = arr.slice(0,arr.length/33);
  for( let a in ar ) {
    var b = a + 1;
  }
}]
, ["for var..in (only 3.3%)", () => {
  var ar = arr.slice(0,arr.length/33);
  for( var a in ar ) {
    var b = a + 1;
  }
}]
, ["Duff's device", () => {
  var len = arr.length;
  var i, n = len % 8 - 1;

  if (n > 0) {
    do {
      var b = arr[len-n] + 1;
    } while (--n); // n must be greater than 0 here
  }
  n = (len * 0.125) ^ 0;
  if (n > 0) { 
    do {
      i = --n <<3;
      var b = arr[i] + 1;
      var c = arr[i+1] + 1;
      var d = arr[i+2] + 1;
      var e = arr[i+3] + 1;
      var f = arr[i+4] + 1;
      var g = arr[i+5] + 1;
      var h = arr[i+6] + 1;
      var k = arr[i+7] + 1;
    }
    while (n); // n must be greater than 0 here also
  }
}]];
function bench(title, f) {
  var t0 = performance.now();
  var res = f();
  return performance.now() - t0; // console.log(`${title} took ${t1-t0} msec`);
}
var globalVarTime = bench( "for-loop without 'var'", () => {
  // Here if you forget to put 'var' so variables'll be global
  for(a = 0, l = arr.length; a < l; ++a)
     var b = arr[a] + 1;
});
var times = benches.map( function(a) {
                      arr = new Array(11111111).fill(255);
                      return [a[0], bench(...a)]
                     }).sort( (a,b) => a[1]-b[1] );
var max = times[times.length-1][1];
times = times.map( a => {a[2] = (a[1]/max)*100; return a; } );
var template = (title, time, n) =>
  `<div>` +
    `<span>${title} &nbsp;</span>` +
    `<span style="width:${3+n/2}%">&nbsp;${Number(time.toFixed(3))}msec</span>` +
  `</div>`;

var strRes = times.map( t => template(...t) ).join("\n") + 
            `<br><br>for-loop without 'var' ${globalVarTime} msec.`;
var $container = document.getElementById("container");
$container.innerHTML = strRes;
body { color:#fff; background:#333; font-family:helvetica; }
body > div > div {  clear:both   }
body > div > div > span {
  float:left;
  width:43%;
  margin:3px 0;
  text-align:right;
}
body > div > div > span:nth-child(2) {
  text-align:left;
  background:darkorange;
  animation:showup .37s .111s;
  -webkit-animation:showup .37s .111s;
}
@keyframes showup { from { width:0; } }
@-webkit-keyframes showup { from { width:0; } }
<div id="container"> </div>

nullqube
źródło
3
@Maykonn prawdopodobnie chciałeś powiedzieć „i działa wszędzie, ale Opera Mini”
dube
3
@Maykonn Którego nie ma na liście w widoku domyślnym, ponieważ 0,18% wszystkich użytkowników ma IE8 i nie powinieneś tracić czasu na próby jego obsługi; w 2018 roku to martwy koń.
dube
1
Jest to zdecydowanie prawda, jeśli weźmiesz pod uwagę wszystkich użytkowników na całym świecie. Niestety, w niektórych częściach świata IE8 ma jeszcze znaczenie.
Maykonn
1
Jeśli mogę, nie tylko różne przeglądarki będą miały różne wyniki przy użyciu różnych metod, ale te same przeglądarki będą miały różne wyniki przy różnych danych wejściowych. Ogromna tablica tylko liczby będzie bardzo zoptymalizowana, a mała mieszana nie.
Kaiido,
1
@Tahlil Thanks.
nullqube,
19

2014 Whilepowraca

Po prostu myśl logicznie.

Spójrz na to

for( var index = 0 , length = array.length ; index < length ; index++ ) {

 //do stuff

}
  1. Musisz utworzyć co najmniej 2 zmienne (indeks, długość)
  2. Musisz sprawdzić, czy indeks jest mniejszy niż długość
  3. Musisz zwiększyć indeks
  4. forpętla 3 parametry

Powiedz mi teraz, dlaczego powinno to być szybsze niż:

var length = array.length;

while( --length ) { //or length--

 //do stuff

}
  1. Jedna zmienna
  2. Brak czeków
  3. indeks jest zmniejszony (maszyny wolą)
  4. while ma tylko jeden parametr

Byłem całkowicie zdezorientowany, gdy Chrome 28 pokazał, że pętla for jest szybsza niż w tym czasie. To musi mieć ben

„Uh, wszyscy używają pętli for, skupmy się na tym podczas programowania dla chrome”.

Ale teraz, w 2014 r., Pętla while wraca do Chrome. jest 2 razy szybszy, w innych / starszych przeglądarkach zawsze był szybszy.

Ostatnio zrobiłem kilka nowych testów. Teraz, w środowisku rzeczywistym, te krótkie kody są nic nie warte, a jsperf nie może właściwie wykonać poprawnie pętli while, ponieważ musi odtworzyć długość tablicy. Zajmuje to również trochę czasu.

nie możesz uzyskać rzeczywistej prędkości pętli while na jsperf.

musisz stworzyć własną funkcję niestandardową i sprawdzić to za pomocą window.performance.now()

I tak ... nie ma mowy, żeby pętla while była po prostu szybsza.

Prawdziwym problemem jest tak naprawdę manipulacja domem / czas renderowania / czas rysowania lub jakkolwiek chcesz to nazwać.

Na przykład mam scenę płótna, w której muszę obliczyć współrzędne i kolizje ... odbywa się to między 10-200 mikrosekund (nie w milisekundach). tak naprawdę renderowanie wszystkiego zajmuje kilka milisekund. Tak samo jak w DOM.

ALE

Istnieje inny bardzo wydajny sposób, loopw niektórych przypadkach użycie for ... na przykład do kopiowania / klonowania tablicy

for(
 var i = array.length ;
 i > 0 ;
 arrayCopy[ --i ] = array[ i ] // doing stuff
);

Zwróć uwagę na ustawienie parametrów:

  1. Tak samo, jak w pętli while, używam tylko jednej zmiennej
  2. Musisz sprawdzić, czy indeks jest większy niż 0;
  3. Jak widać, to podejście jest inne niż normalne dla pętli, której wszyscy używają, ponieważ robię rzeczy wewnątrz trzeciego parametru i również zmniejszam bezpośrednio w tablicy.

Powiedział to, że potwierdza to, że maszyny takie jak -

pisząc, że chciałem zrobić to trochę krócej i usunąć trochę niepotrzebnych rzeczy i napisałem ten w tym samym stylu:

for(
 var i = array.length ;
 i-- ;
 arrayCopy[ i ] = array[ i ] // doing stuff
);

Nawet jeśli jest krótszy, wygląda na to, że użycie jeszcze ijednego czasu wszystko spowalnia. Jest o 1/5 wolniejszy niż poprzednia fori whilepierwsza pętla .

Uwaga:; jest bardzo ważne po za looo bez{}

Nawet jeśli właśnie powiedziałem, że jsperf nie jest najlepszym sposobem testowania skryptów .. dodałem tutaj 2 pętle

http://jsperf.com/caching-array-length/40

A oto kolejna odpowiedź na temat wydajności w javascript

https://stackoverflow.com/a/21353032/2450730

Ta odpowiedź ma pokazać skuteczne sposoby pisania javascript. Więc jeśli nie możesz tego przeczytać, zapytaj, a otrzymasz odpowiedź lub książkę o javascript http://www.ecma-international.org/ecma-262/5.1/

cocco
źródło
Ta odpowiedź zaczyna się bardzo dobrze . Zauważyłem, że przez ostatnie kilka lat forbyło to szybsze niż whilekiedyś, i kiedyś czytałem w crome-dev, że właśnie z tego powodu wspomniałeś. Byłoby tylko kwestią czasu, zanim whileznów to nadrabi. Od tego momentu logika w pierwszej części twojej odpowiedzi będzie obowiązywała (jeszcze raz, tak)! Jednak nowoczesne implementacje nie podążają już sztywno za każdym krokiem określonym w ecma (optymalizują). Ponieważ teraz twój silnik nie jest już najbardziej zauważalnym wąskim gardłem, możesz teraz zauważyć brak pamięci podręcznej procesora w pętlach zwrotnych !
GitaarLAB,
Wyjaśnij, więc może poprawię odpowiedź lub nauczę się czegoś nowego. przy okazji odpowiedź ma już ponad rok ... przeglądarki mogły się zmieniać z czasem, jak zawsze ...
cocco
Moim zdaniem, podczas gdy (--length) jest złe, ponieważ technicznie działa, ponieważ 0 jest fałszem, 0 i fałsz nie są tak naprawdę semantycznie rzecz biorąc tym samym.
scott.korin
tak ... to jest teraz starszy post ... ale tak, uwielbiam prostotę tego czasu. I na pewno, jak wspominasz o tym w obu przypadkach, musisz wiedzieć, co napisać. Z drugiej strony nigdy nie musiałem zapętlać liczb ujemnych.
cocco
9
„Maszyny wolą to” brzmi jak zdanie z reklamy detergentu do prania
CocoaBean
11

http://jsperf.com/caching-array-length/60

Najnowsza wersja testu, którą przygotowałem (wykorzystując ponownie starszą), pokazuje jedną rzecz.

Długość buforowania nie jest tak ważna, ale nie szkodzi.

Każde pierwsze uruchomienie powyższego testu (na świeżo otwartej karcie) daje najlepsze wyniki dla 4 ostatnich fragmentów (3, 5, 7 i 10 na wykresach) w Chrome, Opera i Firefox w moim Debian Squeeze 64-bitowym ( mój komputer stacjonarny) ). Kolejne przebiegi dają całkiem inny wynik.

Wnioski dotyczące wydajności są proste:

  • Przejdź do pętli for (forward) i przetestuj za pomocą !==zamiast <.
  • Jeśli nie będziesz musiał ponownie używać tablicy później, to podczas gdy pętla na zmniejszonej długości i shift()tablica niszcząca jest również wydajna.

tl; dr

Obecnie (2011.10) poniższy wzór wydaje się najszybszy.

for (var i = 0, len = arr.length; i !== len; i++) {
    ...
}

Pamiętaj, że buforowanie arr.lengthnie jest tutaj kluczowe, więc możesz po prostu sprawdzić, i !== arr.lengthczy wydajność nie spadnie, ale otrzymasz krótszy kod.


PS: Wiem, że we fragmencie z shift()jego wynikiem można było użyć zamiast dostępu do 0-tego elementu, ale jakoś przeoczyłem to po ponownym użyciu poprzedniej wersji (która miała błędne pętle while), a później nie chciałem stracić już uzyskanych wyników.

przemoc
źródło
Czy tworzysz zmienną w pętli, np. Niech current = arr [i] może obniżyć wydajność (przydział dużej pamięci)? A może lepiej zadeklarować prąd przed pętlą? Lub użyj arr [i] we wszystkich miejscach w pętli?
Makarow Sergey
8

„Najlepszy” jak w czystej wydajności? lub wydajność ORAZ czytelność?

„Najlepsza” czysta wydajność to ta, która wykorzystuje pamięć podręczną i operator prefiksu ++ (moje dane: http://jsperf.com/caching-array-length/189 )

for (var i = 0, len = myArray.length; i < len; ++i) {
  // blah blah
}

Twierdziłbym, że pętla for bez pamięci podręcznej zapewnia najlepszą równowagę między czasem wykonania a czasem odczytu programisty. Każdy programista, który zaczął od C / C ++ / Java, nie zmarnuje ms na przeczytanie tego

for(var i=0; i < arr.length; i++){
  // blah blah
}
valbaca
źródło
2
+1 za czytelność. Bez względu na to, jak dobrze lensię nazywa, zawsze trzeba będzie wykonać podwójne podejście do pierwszej pętli. Zamiar drugiej pętli jest oczywisty.
Josh Johnson
7

** buforuj długość tablicy w pętli, uniknie się kilku sekund. Zależy od elementów w tablicy, jeśli jest więcej elementów w tablicy, istnieje znacząca różnica w odniesieniu do Ms *

**

sArr; //Array[158];

for(var i = 0 ; i <sArr.length ; i++) {
 callArray(sArr[i]); //function call
}

***end: 6.875ms***

**

**

sArr; //Array[158];
for(var i = 0,len = sArr.length ; i < len ; i++) {
  callArray(sArr[i]); //function call
}

***end: 1.354ms***

**

Shushanth Pallegar
źródło
6

To zdecydowanie najszybszy sposób ...

var el;
while (el = arr.shift()) {
  el *= 2;
}

Weź pod uwagę, że spowoduje to zużycie tablicy, zjedzenie jej i pozostawienie niczego ...

Sergio
źródło
2
arr.shift();zamiast, arr.pop() aby uniknąć odwrócenia tablicy.
Tintu C Raju
1
@Gargaroz, jeśli otrzymujesz JSON z usługi internetowej, na przykład usługi czatu lub elementów w katalogu produktów. Inną sytuacją, w której wystarczy raz użyć tablicy, może być na przykład wykres, który otrzymuje wiele współrzędnych w odstępach czasu. Jest wiele przykładów.
Sergio,
Fajnie, dziękuję za wyjaśnienie, bardzo miło z twojej strony; czy możesz wskazać mi kierunek, w którym mogę znaleźć dalsze przykłady wykorzystania tego rodzaju pętli?
Gargaroz
1
Obecnie w Chrome 53 i Firefox 48 jest to jedno z najwolniejszych rozwiązań - sprawdź na perfjs.info/array-iteration
Pencroff 15.09.16
1
@Arereza się zgadzam, mam na to komentarz również w mojej odpowiedzi.
Sergio,
4

To rok 2017 .

Zrobiłem kilka testów.

https://jsperf.com/fastest-way-to-iterate-through-an-array/

Wygląda na to, że whilemetoda jest najszybsza w Chrome.

Wygląda lewej zmniejszania ( --i) jest znacznie szybciej niż inni ( ++i, i--, i++) na Firefox.

Takie podejście jest średnio na czczo. Ale iteruje tablicę w odwrotnej kolejności.

let i = array.length;
while (--i >= 0) {
    doSomething(array[i]);
}

Jeśli ważne jest zlecenie forward, skorzystaj z tego podejścia.

let ii = array.length;
let i = 0;
while (i < ii) {
    doSomething(array[i]);
    ++i;
}
SeregPie
źródło
3
Używając słowa kluczowego let, faktycznie porównujesz wydajność tworzenia zakresu zamiast wydajności pętli. Użycie let i = 0, ii = array.lengthw twoich forpętlach stworzy nowy zakres dla tych zmiennych wewnątrz forbloku. Twoje whileprzykłady nie tworzą nowego zakresu dla zmiennych wewnątrz whilebloku i dlatego są one szybsze. Jeśli użyjesz varzamiast letw pętli for, zobaczysz, jak pętle są nadal tak szybkie jak w 2017 roku, ale bardziej czytelne.
CGodo
Oto jsperf tego, o czym mówię: jsperf.com/javascript-loop-testing-let-vs-var
CGodo
To tylko problem w Chrome. W innych przeglądarkach vari letmają taką samą wydajność - stackoverflow.com/a/32345435/1785975
SeregPie
Ciekawy. W każdym razie stwierdzenie „ whilebycie szybszym w Chrome” nie jest trafne. Tylko w przypadku używania letze względu na problemy z wydajnością tego słowa kluczowego w Chrome. Jeśli używasz varlub z innymi przeglądarkami fori whilesą one prawie takie same, czasami forjest nawet szybsze w zależności od testu porównawczego, i jest bardziej kompaktowy i czytelny imho.
CGodo,
2

Zawsze piszę w pierwszym stylu.

Nawet jeśli kompilator jest wystarczająco inteligentny, aby zoptymalizować go pod kątem tablic, ale nadal jest inteligentny, jeśli używamy tutaj DOMNodeList lub jakiegoś skomplikowanego obiektu o obliczonej długości?

Wiem, jakie jest pytanie o tablice, ale myślę, że dobrą praktyką jest pisanie wszystkich pętli w jednym stylu.

Olegas
źródło
1
var arr = []; // The array
var i = 0;
while (i < arr.length) {
    // Do something with arr[i]
    i++;
}

i ++ jest szybszy niż ++ i, --i i i--

Możesz także zapisać ostatnią linię, wykonując arr [i ++], kiedy ostatni raz potrzebujesz dostępu do i (ale może to być trudne do debugowania).

Możesz to przetestować tutaj (z innymi testami pętli): http://jsperf.com/for-vs-whilepop/5

Forestrf
źródło
1
Obecnie w Chrome 53 to prawda, ale Firefox 48 ma tę samą prędkość - sprawdź na perfjs.info/array-iteration
Pencroff 15.09.16
thunderguy.com/semicolon/2002/08/13/… mówi, że ++ijest szybszy ...
IMTheNachoMan
1

We wrześniu 2017 r. Te testy jsperf pokazują następujący wzorzec, który jest najbardziej wydajny w Chrome 60:

function foo(x) {
 x;
};
arr.forEach(foo);

Czy ktoś może się rozmnażać?

John Vandivier
źródło
Tak, wydaje się być najszybszy, jednak spróbuj uruchomić to w IE11, a te opcje są najwolniejsze. A w Firefoksie 55.03 „stara pęknięta pamięć podręczna” osiąga 12 mil, co oznacza oszałamiającą wydajność w porównaniu do 3,3 tys. Chromu. Aby zachować stałą wydajność we wszystkich przeglądarkach, należy użyć najszybszej średniej pętli dla każdej przeglądarki.
Plippie
0

Próbowałem innych sposobów na iterację ogromnej tablicy i odkryłem, że zmniejszenie o połowę długości tablicy, a następnie iteracja obu połówek w jednej pętli jest szybsze. Tę różnicę wydajności można zobaczyć podczas przetwarzania ogromnych tablic .

var firstHalfLen =0;
var secondHalfLen = 0;
var count2=0;
var searchterm = "face";
var halfLen = arrayLength/2;
if(arrayLength%2==halfLen)
{
   firstHalfLen = Math.ceil(halfLen);
   secondHalfLen=Math.floor(halfLen);
}
else
{
   firstHalfLen=halfLen;
   secondHalfLen=halfLen;
}
for(var firstHalfCOunter=0,secondHalfCounter = arrayLength-secondHalfLen;
    firstHalfCOunter < firstHalfLen;
    firstHalfCOunter++)
{
  if(mainArray[firstHalfCOunter].search(new RegExp(searchterm, "i"))> -1)
  {
    count2+=1;
  }
  if(secondHalfCounter < arrayLength)
  {
    if(mainArray[secondHalfCounter].search(new RegExp(searchterm, "i"))> -1)
    {
        count2+=1;
    }
    secondHalfCounter++; 
  }
}

Pewne porównanie wydajności (przy użyciu timer.js) między buforowaną długością pętli for VS a powyższą metodą.

http://jsfiddle.net/tejzpr/bbLgzxgo/

tejzpr
źródło
0

Kolejny test jsperf.com: http://jsperf.com/while-reverse-vs-for-cached-length

Pętla rewersyjna wydaje się być najszybsza. Jedynym problemem jest to, że podczas gdy (--i) zatrzyma się na 0. Jak mogę wtedy uzyskać dostęp do tablicy [0] w mojej pętli?

Moritz Schmitz przeciwko Hülst
źródło
2
Jeśli to zrobisz, while (i--)prawdziwość izostanie przetestowana przed zmniejszeniem, a nie zmniejszeniem, a następnie sprawdzeniem prawdziwości.
Justin Fisher
0

Podczas gdy pętla jest nieco szybsza niż dla pętli.

var len = arr.length;
while (len--) {
    // blah blah
}

Zamiast tego użyj pętli while

Azhar Zafar
źródło
-1

Najbardziej eleganckim rozwiązaniem, jakie znam, jest użycie mapy.

var arr = [1,2,3];
arr.map(function(input){console.log(input);});
Dan
źródło
46
Pytanie nie wymaga najwolniejszego sposobu iteracji przez pętlę
eoleary
-1

Spróbuj tego:

var myarray =[],
i = myarray.lenght;
while(i--){
// do somthing
}
li bing zhao
źródło
-1

Szybszym sposobem zapętlenia tablicy jest użycie filtra. Metoda filter () tworzy nową tablicę ze wszystkimi elementami, które pomyślnie przejdą test zaimplementowany przez podaną funkcję.

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

const words = ['Floccinaucinihilipilification', 'limit', 'elite', 'Hippopotomonstrosesquipedaliophobia', 'destruction', 'present'];

const result = words.filter(word => word.length > 6);

console.log(new Date(), result);

Z mojego doświadczenia zawsze wolę filtry, mapę itp.

Rigin Oommen
źródło
Pytanie dotyczy iteracji po tablicy w jak najkrótszym czasie bez kopiowania tablicy do nowej tablicy.
Rahul Kadukar
-1

Począwszy od 2019 roku WebWorker stał się bardziej popularny, w przypadku dużych zestawów danych możemy używać WebWorker do przetwarzania znacznie szybciej dzięki pełnemu wykorzystaniu procesorów wielordzeniowych.

Mamy również plik Parallel.js, dzięki któremu WebWorker jest znacznie łatwiejszy w użyciu do przetwarzania danych.

Stackia
źródło