MDN mówi, że for await...of
ma dwa przypadki użycia:
for await...of
Instrukcja tworzy pętlę iteracji nad asynchroniczny iterable obiektów, jak również na iterables synchronizacji ...
Wcześniej zdawałem sobie sprawę z pierwszego: asynchroniczne iterowanie przy użyciu Symbol.asyncIterator
. Ale interesuje mnie teraz to drugie: iteracje synchroniczne.
Poniższy kod iteruje iterację synchroniczną - tablicę obietnic. Wydaje się, że blokuje postęp w wypełnianiu każdej obietnicy.
async function asyncFunction() {
try {
const happy = new Promise((resolve)=>setTimeout(()=>resolve('happy'), 1000))
const sad = new Promise((_,reject)=>setTimeout(()=>reject('sad')))
const promises = [happy, sad]
for await(const item of promises) {
console.log(item)
}
} catch (err) {
console.log(`an error occurred:`, err)
}
}
asyncFunction() // "happy, an error occurred: sad" (printed in quick succession, after about 5 seconds)
Zachowanie wydaje się podobne do oczekiwania na każdą obietnicę po kolei, zgodnie z logiką przedstawioną poniżej. Czy to twierdzenie jest prawidłowe?
Pytam, ponieważ ten wzór kodu ma niejawny odrzucenia wire-up pułapki że Promise.all
i Promise.allSettled
unikania, a wydaje mi się dziwne, że ten wzór będzie wyraźnie wspierane przez język.
źródło
for await... of
synchronicznych iteracji jest poprawny, a jeśli tak, to czy ma znaczenie to, że ten wzorzec może emitować nieobsługiwane błędy odrzucenia?Odpowiedzi:
Tak, to dziwne i nie powinieneś tego robić. Nie iteruj tablic obietnic, prowadzi to dokładnie do wspomnianego problemu nieobsługiwanych odrzuceń .
Dlaczego to jest obsługiwane w języku? Kontynuacja niedbałej semantyki.
Dokładne uzasadnienie można znaleźć w tym komentarzu do kwestii omawiającej tę część wniosku :
źródło
unhandledrejection
wydarzenia?window.addEventListener('unhandledrejection',...
skrócie: jest to jedyny przypadek, jaki mogę sobie przypomnieć, z tego rodzaju emisji błędów przez JavaScript. Jednak prawie na pewno się mylę, że tak myślę. Wreszcie: czy emisja tego „błędu” naprawdę naprawdę ma znaczenie poza tym, że w konsoli pojawia się niechciany komunikat o błędzie?sad
Obietnica nie będącawait
ed kiedy to się nie powiedzie - że potrzebuje kod do końca czeka nahappy
zanim zacznie czekać nasad
.sad
Obietnica zawodzi przedhappy
ustąpienia objawów. (Promise.all
jest narzędziem, które lepiej nadaje się do tego przypadku użycia)źródło
Promise.all
jest lepsze rozwiązanie, dlaczego język obsługuje tę składnię?for await...of
można łatwo wdrożyć, aby po prostu wyliczyć asynchroniczne iterowalne. Ale zadbali o to, by wyliczyć synchroniczne iterowalne (ale z (pozornie?) Pułapką). Dlaczego?for await ... of
akceptuje synchroniczne iteracje? Wyobrażam sobie, że mogę wspierać generatory asynchroniczne, które warunkowo mogą zwracać elementy synchroniczne.