Wydajność Javascript: „for” vs „forEach” [zamknięte]

104

Jaki jest obecny standard w 2017 roku w Javascript z pętlami for () w porównaniu z .forEach.

Obecnie pracuję nad „Web Dev Bootcamp” Colta Steelesa na Udemy i on faworyzuje forEachgo forw swoich naukach. Szukałem jednak różnych rzeczy podczas ćwiczeń w ramach kursu i znajduję coraz więcej zaleceń, aby używać forraczej -loopa niż forEach. Większość ludzi uważa, że ​​pętla for jest bardziej wydajna.

Czy to się zmieniło od czasu napisania kursu (około 2015 roku), czy też są ich naprawdę wady i zalety każdego z nich, czego nauczysz się z większym doświadczeniem.

Każda rada byłaby bardzo mile widziana.

tonyrobbins
źródło
11
Po co przywiązywać się do czyjegoś subiektywnego wyobrażenia o standardzie z 2017 roku? Przyjmij ponadczasowy standard, taki jak pisanie czystego, łatwego w utrzymaniu kodu, wiedząc, że inżynierowie ciężko pracują, aby najczęściej używane konstrukcje były bardzo wydajne, a następnie optymalizują wydajność, gdy masz określony problem z wydajnością
2
Tubylec forjest trudny do pokonania dla czystej prędkości. forEach()wywołuje wywołanie zwrotne dla każdej iteracji; więc to oczywiście wiąże się z pewnym obciążeniem.
kanon
1
będąc programistą, którego rzadko używam dla lub na zawsze, większość pracy jest wykonywana przy użyciu metod mapowania, filtrowania lub redukcji.
AT
12
@AT, o ile nie jesteś jednym z tych facetów, którzy używają mapwyłącznie do iteracji i odrzucają nową tablicę, którą generuje. Nie wiem, ile osób musiałem poprawić w przypadku tego konkretnego wyboru funkcji na tej samej stronie.
kanon
1
@canon zgodził się, wybór pętli jest ważny i przy wyborze należy pamiętać o wynikach i pozostałościach takich metod. Uważam, że ze względu na czytelność należy unikać zwykłego „pętli for”.
AT

Odpowiedzi:

202

dla

forpętle są znacznie wydajniejsze. Jest to konstrukcja pętli zaprojektowana specjalnie do iteracji, gdy warunek jest prawdziwy , jednocześnie oferując mechanizm krokowy (zwykle w celu zwiększenia iteratora). Przykład:

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

Nie jest to sugerować, że za będzie -loops zawsze być bardziej wydajny, wystarczy, że silniki JS i przeglądarek zoptymalizowano je tak być. Przez lata pojawiały się kompromisy co do tego, która konstrukcja pętli jest bardziej wydajna (np. Redukuj, odwracaj podczas itd.) - różne przeglądarki i silniki JS mają własne implementacje, które oferują różne metodologie, aby generować te same wyniki. Ponieważ przeglądarki dalej optymalizują się, aby sprostać wymaganiom wydajności, teoretycznie [].forEachmożna je zaimplementować w taki sposób, aby był szybszy lub porównywalny z for.

Korzyści:

  • wydajny
  • wczesne zakończenie pętli (wyróżnienia breaki continue)
  • kontrola warunku ( i<nmoże być dowolna i nie jest powiązana z rozmiarem tablicy)
  • zmienny zasięg ( var iliście idostępne po zakończeniu pętli)

dla każdego

.forEachto metody, które głównie iterują po tablicach (także po innych wyliczalnych obiektach , takich jak Mapi Set). Są nowsze i zapewniają subiektywnie łatwiejszy do odczytania kod. Przykład:

[].forEach((val, index)=>{
   ...
});

Korzyści:

  • nie wymaga konfiguracji zmiennych (iteruje po każdym elemencie tablicy)
  • funkcje / funkcje-strzałek określają zakres zmiennej do bloku
    W powyższym przykładzie valbyłby to parametr nowo utworzonej funkcji. W ten sposób wszystkie zmienne wywoływane valprzed pętlą będą miały swoje wartości po jej zakończeniu.
  • subiektywnie łatwiejsze w utrzymaniu, ponieważ może być łatwiej zidentyfikować, co robi kod - iteruje po wyliczalnym; podczas gdy pętla for może być używana dla dowolnej liczby schematów pętli

Występ

Wydajność to trudny temat, który zwykle wymaga pewnego doświadczenia, jeśli chodzi o przezorność lub podejście. Aby określić z wyprzedzeniem (podczas opracowywania), ile optymalizacji może być wymagane, programista musi mieć dobre wyobrażenie o wcześniejszych doświadczeniach z przypadkiem problemowym, a także dobre zrozumienie potencjalnych rozwiązań.

Korzystanie z jQuery w niektórych przypadkach może być czasami zbyt wolne (doświadczony programista może to wiedzieć), podczas gdy innym razem może nie stanowić problemu, w takim przypadku zgodność biblioteki z różnymi przeglądarkami i łatwość wykonywania innych funkcji (np. AJAX, obsługa zdarzeń) byłaby warta zaoszczędzonego czasu na rozwój (i utrzymanie).

Innym przykładem jest to, że gdyby wydajność i optymalizacja były wszystkim, nie byłoby innego kodu niż maszyna lub zespół. Oczywiście tak nie jest, ponieważ istnieje wiele różnych języków wysokiego i niskiego poziomu, z których każdy ma swoje własne kompromisy. Te kompromisy obejmują między innymi specjalizację, łatwość i szybkość programowania, łatwość i szybkość konserwacji, zoptymalizowany kod, kod wolny od błędów itp.

Podejście

Jeśli nie masz dobrego zrozumienia, czy coś będzie wymagało zoptymalizowanego kodu, ogólnie dobrą zasadą jest, aby najpierw napisać kod, który można konserwować. Stamtąd możesz przetestować i wskazać, co wymaga więcej uwagi, gdy jest to wymagane.

To powiedziawszy, pewne oczywiste optymalizacje powinny być częścią ogólnej praktyki i nie wymagają żadnej refleksji. Weźmy na przykład pod uwagę następującą pętlę:

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

Dla każdej iteracji pętli JavaScript arr.lengthpobiera operację kalkulacji kosztów wyszukiwania kluczy w każdym cyklu. Nie ma powodu, dla którego nie powinno to być:

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

Robi to samo, ale pobiera tylko arr.lengthraz, buforując zmienną i optymalizując kod.

vol7ron
źródło
25
Doskonała, dokładna, nie arogancka odpowiedź, niezwiązana z jednym punktem w czasie, wdrożeniem lub testem mikro-testowym.
1
Idealnie, właśnie tego szukałem i daje o wiele większą głębię niż wideo. Naprawdę to doceniam, ponieważ bycie nowym jest tak wiele do nauczenia, a są to rzeczy, które łatwo jest pominąć, po prostu faworyzując jedną nad drugą bez powodu, który mógłby przeszkadzać ci w przyszłości. Wielkie dzięki!
tonyrobbins
2
For-loop często ma przewagę pod względem debugowania: są trudne do wejścia, punktu przerwania i inspekcji. Dzięki forEach () dodatkowy poziom wywołania zwrotnego może trochę skomplikować sprawę.
Eric Grange,
1
@FelipeBuccioni dziękuję, właściwie zamierzałem się temu przyjrzeć, ponieważ myślę, że silniki teraz sprawdzą, czy tablica zostanie zmutowana, aby określić, czy długość jest buforowana. Chociaż, dla celów starszych, myślę, że silniki optymalizacji nie były tak hojne, a długość była hitem wydajności w każdej iteracji. Rzucę okiem na twój artykuł i uwzględnię go w odpowiedzi, gdy będę miał czas, lub miejmy nadzieję, że wybitny członek społeczności wprowadzi dla mnie
poprawkę
6
Naprawdę podoba mi się wyjaśnienie w tej odpowiedzi i zdanie [...], if performance and optimization was everything, there would be no other code than machine or assembly.. Uważam, że w letprzypadku deklaracji zmiennej lokalnej o zasięgu blokowym druga korzyść forEachnie jest już przewagą nad forpętlą, chyba że w środowisku bez wsparcia let.
user7393973