Jak sugeruje tytuł. Jak mam to zrobic?
Chcę zadzwonić whenAllDone()
po przejściu pętli forEach przez każdy element i wykonaniu asynchronicznego przetwarzania.
[1, 2, 3].forEach(
function(item, index, array, done) {
asyncFunction(item, function itemDone() {
console.log(item + " done");
done();
});
}, function allDone() {
console.log("All done");
whenAllDone();
}
);
Czy jest możliwe, aby działało w ten sposób? Kiedy drugim argumentem forEach jest funkcja zwrotna, która jest uruchamiana po przejściu wszystkich iteracji?
Oczekiwany wynik:
3 done
1 done
2 done
All done!
javascript
node.js
asynchronous
callback
Dan Andreasson
źródło
źródło
forEach
metoda tablicowa miaładone
parametrallDone
wywołania zwrotnego i wywołanie zwrotne!Odpowiedzi:
Array.forEach
nie zapewnia tej subtelności (och, gdyby tak było), ale istnieje kilka sposobów na osiągnięcie tego, co chcesz:Za pomocą prostego licznika
(dzięki @vanuan i innym) Takie podejście gwarantuje, że wszystkie elementy zostaną przetworzone przed wywołaniem wywołania zwrotnego „gotowe”. Musisz użyć licznika, który jest aktualizowany w wywołaniu zwrotnym. W zależności od wartości parametru indeksu nie zapewnia tej samej gwarancji, ponieważ kolejność zwrotu operacji asynchronicznych nie jest gwarantowana.
Korzystanie z obietnic ES6
(w starszych przeglądarkach można użyć biblioteki obietnic):
Przetwarzaj wszystkie żądania gwarantujące synchroniczne wykonanie (np. 1, 2, 3, 3)
Przetwarzaj wszystkie żądania asynchroniczne bez wykonania „synchronicznego” (2 może zakończyć się szybciej niż 1)
Korzystanie z biblioteki asynchronicznej
Istnieją inne biblioteki asynchroniczne , z których najpopularniejsze to asynchroniczne , które zapewniają mechanizmy wyrażania tego, co chcesz.
EdytowaćTreść pytania została poddana edycji w celu usunięcia wcześniej zsynchronizowanego przykładowego kodu, więc zaktualizowałem swoją odpowiedź, aby wyjaśnić. W oryginalnym przykładzie wykorzystano synchroniczny kod podobny do modelowania zachowania asynchronicznego, dlatego zastosowano następujące zasady:
array.forEach
jest zsynchronizowany i tak też jestres.write
, więc możesz po prostu oddzwonić po połączeniu, aby foreach:źródło
if(index === array.length - 1)
i usunąćitemsProcessed
Jeśli napotkasz funkcje asynchroniczne i chcesz się upewnić, że przed wykonaniem kodu zakończy on swoje zadanie, zawsze możemy skorzystać z funkcji wywołania zwrotnego.
Na przykład:
Uwaga:
functionAfterForEach
to funkcja, która ma być wykonana po zakończeniu wszystkich zadań.asynchronous
jest funkcją asynchroniczną wykonywaną wewnątrz foreach.źródło
Mam nadzieję, że to rozwiąże problem, zwykle pracuję z tym, gdy muszę wykonać forEach z asynchronicznymi zadaniami wewnątrz.
z
źródło
Dziwne, ile błędnych odpowiedzi zostało podanych w przypadku asynchronicznym ! Można po prostu pokazać, że sprawdzanie indeksu nie zapewnia oczekiwanego zachowania:
wynik:
Jeśli sprawdzimy
index === array.length - 1
, oddzwonienie zostanie wywołane po zakończeniu pierwszej iteracji, podczas gdy pierwszy element jest nadal w toku!Myślę, że aby rozwiązać ten problem bez korzystania z zewnętrznych bibliotek, takich jak asynchronizacja, najlepiej jest zapisać długość listy i zmniejszyć ją po każdej iteracji. Ponieważ jest tylko jeden wątek, jesteśmy pewni, że nie ma szans na warunki wyścigowe.
źródło
W ES2018 możesz używać iteratorów asynchronicznych:
źródło
Moje rozwiązanie bez obietnicy (zapewnia to, że każda akcja zostanie zakończona przed rozpoczęciem kolejnej):
źródło
źródło
Jest to rozwiązanie dla Node.js, które jest asynchroniczne.
za pomocą pakietu async npm.
(JavaScript) Synchronizacja forEach Loop z wywołaniami zwrotnymi wewnątrz
źródło
Moje rozwiązanie:
Przykład:
źródło
Wypróbowuję Easy Way, aby go rozwiązać, podziel się nim z tobą:
request
jest funkcją biblioteki mssql w węźle js. Może to zastąpić każdą funkcję lub dowolny kod. Powodzeniaźródło
źródło
Nie powinieneś potrzebować oddzwaniania do iteracji po liście. Po prostu dodaj
end()
połączenie po pętli.źródło
res.write
NIE jest operacją asynchroniczną, więc kod nie będzie działał.Proste rozwiązanie byłoby następujące
źródło
Co powiesz na setInterval, aby sprawdzić pełną liczbę iteracji, daje gwarancję. Nie jestem pewien, czy nie przeładuje on zakresu, ale używam go i wydaje się, że to on
źródło