Mam pytanie dotyczące natywnej Array.forEach
implementacji JavaScript: czy zachowuje się asynchronicznie? Na przykład, jeśli zadzwonię:
[many many elements].forEach(function () {lots of work to do})
Czy to nie będzie blokować?
javascript
arrays
asynchronous
foreach
node.js
R. Gr.
źródło
źródło
Odpowiedzi:
Nie, to blokuje. Zobacz specyfikację algorytmu .
Jednak w MDN podano łatwiejsze do zrozumienia wdrożenie :
Jeśli musisz wykonać dużo kodu dla każdego elementu, powinieneś rozważyć zastosowanie innego podejścia:
a następnie zadzwoń za pomocą:
To nie byłoby wtedy blokowaniem. Przykład pochodzi z wysokiej wydajności JavaScript .
Inną opcją mogą być pracownicy sieci .
źródło
forEach
ma nie blokować naawait
sprawozdaniach za przykład i należy raczej używaćfor
pętli: stackoverflow.com/questions/37962880/...await
wewnętrznychasync
. AleforEach
nie wie, jakie są funkcje asynchroniczne. Należy pamiętać, że funkcje asynchroniczne to tylko funkcje zwracające obietnicę. Czy spodziewałbyś się, żeforEach
spełnisz obietnicę zwróconą z wywołania zwrotnego?forEach
całkowicie ignoruje wartość zwrotną z wywołania zwrotnego. Byłby w stanie obsłużyć wywołanie zwrotne asynchroniczne tylko wtedy, gdyby sam był asynchroniczny.Jeśli potrzebujesz wersji asynchronicznej
Array.forEach
i podobnej, są one dostępne w module „async” Node.js: http://github.com/caolan/async ... jako bonus ten moduł działa również w przeglądarce .źródło
eachSeries
zamiast tego.Istnieje częsty wzorzec wykonywania bardzo ciężkich obliczeń w węźle, który może dotyczyć ciebie ...
Węzeł jest jednowątkowy (jako celowy wybór projektu zobacz Co to jest Node.js? ); oznacza to, że może wykorzystywać tylko jeden rdzeń. Nowoczesne urządzenia mają 8, 16 lub nawet więcej rdzeni, więc może to pozostawić 90% maszyny w stanie bezczynności. Typowym wzorcem dla usługi REST jest odpalanie jednego procesu węzła na rdzeń i umieszczanie ich za lokalnym modułem równoważenia obciążenia, takim jak http://nginx.org/ .
Rozwidlając dziecko - w przypadku tego, co próbujesz zrobić, istnieje inny wspólny wzór, odrywając proces dziecka od ciężkiego podnoszenia. Plusem jest to, że proces potomny może wykonywać ciężkie obliczenia w tle, podczas gdy proces nadrzędny reaguje na inne zdarzenia. Problem polega na tym, że nie możesz / nie powinieneś współdzielić pamięci z tym procesem potomnym (nie bez DUŻYCH zniekształceń i trochę natywnego kodu); musisz przekazywać wiadomości. Będzie to działało pięknie, jeśli rozmiar danych wejściowych i wyjściowych jest niewielki w porównaniu do obliczeń, które należy wykonać. Możesz nawet uruchomić potomny proces node.js i użyć tego samego kodu, którego używałeś wcześniej.
Na przykład:
źródło
Array.forEach
jest przeznaczony do obliczania rzeczy, które nie czekają, i nie ma nic do zyskania, czyniąc obliczenia asynchroniczne w pętli zdarzeń (pracownicy sieci dodają przetwarzanie wieloprocesowe, jeśli potrzebujesz obliczeń wielordzeniowych). Jeśli chcesz poczekać na zakończenie wielu zadań, użyj licznika, który możesz owinąć w klasę semaforów.źródło
Edytuj 2018-10-11: Wygląda na to, że istnieje spora szansa, że opisany poniżej standard może nie przejść, rozważ potokowanie jako alternatywę (nie zachowuje się dokładnie tak samo, ale metody można zaimplementować w podobnej rezydencji).
Właśnie dlatego jestem podekscytowany es7, w przyszłości będziesz mógł zrobić coś takiego jak poniższy kod (niektóre specyfikacje nie są kompletne, więc używaj ostrożnie, postaram się to aktualizować). Ale w zasadzie używając nowego operatora :: bind, będziesz mógł uruchomić metodę na obiekcie tak, jakby prototyp obiektu zawierał tę metodę. np. [Obiekt] :: [Metoda], gdzie normalnie wywołujesz [Obiekt]. [ObjectsMethod]
Pamiętaj, aby zrobić to dzisiaj (24 lipca-16 lipca) i sprawić, aby działał we wszystkich przeglądarkach, musisz transponować kod, aby uzyskać następujące funkcje: Import / Eksport , Funkcje strzałek , Obietnice , Async / Oczekiwanie i najważniejsze powiązanie funkcji . Poniższy kod można zmodyfikować tak, aby używał tylko wiązania funkcji, jeśli jest to konieczne, cała ta funkcjonalność jest dziś dostępna za pomocą babel .
YourCode.js (gdzie „ dużo pracy do wykonania ” musi po prostu zwrócić obietnicę, rozwiązując ją po zakończeniu pracy asynchronicznej).
ArrayExtensions.js
źródło
Jest to krótka funkcja asynchroniczna, z której można korzystać bez konieczności korzystania z bibliotek stron trzecich
źródło
Istnieje pakiet na npm dla łatwego asynchronicznego dla każdej pętli .
Kolejna odmiana dla AllAsync
źródło
Możliwe jest kodowanie nawet takiego rozwiązania, na przykład:
Z drugiej strony jest znacznie wolniejszy niż „za”.
W przeciwnym razie doskonała biblioteka Async może to zrobić: https://caolan.github.io/async/docs.html#each
źródło
Oto mały przykład, który możesz uruchomić, aby go przetestować:
Wytworzy coś takiego (jeśli zajmie to za dużo / dużo czasu, zwiększ / zmniejsz liczbę iteracji):
źródło
Zastosowanie Promise.each z Bluebird bibliotece.
Ta metoda iteruje tablicę lub obietnicę tablicy, która zawiera obietnice (lub kombinację obietnic i wartości) z daną funkcją iteratora z podpisem (wartość, indeks, długość), gdzie wartość jest wartością rozstrzygniętą odpowiednia obietnica w tablicy wejściowej. Iteracja odbywa się szeregowo.Jeśli funkcja iteratora zwraca obietnicę lub niemożliwą, wówczas wynik obietnicy jest oczekiwany przed kontynuowaniem następnej iteracji. Jeśli jakakolwiek obietnica w tablicy wejściowej zostanie odrzucona, wówczas również zwrócona obietnica zostanie odrzucona.
Jeśli wszystkie iteracje zakończą się powodzeniem, Promise.each rozpoznaje pierwotną tablicę niezmodyfikowaną . Jeśli jednak jedna iteracja odrzuci lub popełni błąd, Promise.each natychmiast przerywa wykonywanie i nie przetwarza dalszych iteracji. Błąd lub odrzucona wartość jest w tym przypadku zwracana zamiast oryginalnej tablicy.
Ta metoda jest przeznaczona do stosowania w przypadku działań niepożądanych.
źródło