Bug #056
🪲 Znajdź buga
async function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms)
})
}
async function main() {
const numbers = [1, 2, 3]
const store = []
numbers.forEach(async (num) => {
await sleep(1000)
store.push(num)
})
console.log(store)
}
main()
Chcemy zasymulować wykonanie asynchronicznych operacji na danych.
Funkcja sleep()
zatrzymuje działanie kodu na określoną ilość milisekund symulując asynchroniczne operacje. Następnie przetworzone dane z pierwotnej tablicy numbers
chcemy dodać do nowej store
.
Czy powyższy kod zadziała prawidłowo?
Co zostanie zalogowane do konsoli?
🧪 Rozwiązanie
async function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms)
})
}
async function main() {
const numbers = [1, 2, 3]
const store = []
const promises = numbers.map(async (num) => {
await sleep(1000)
store.push(num)
})
await Promise.all(promises)
console.log(store)
}
main()
W przykładzie z błędem do konsoli zostanie zalogowana pusta tablica []
. Nasz kod nie zadziała więc zgodnie z planem.
Metoda forEach()
, wywołuje funkcję przekazaną w argumencie jako callback w sposób synchroniczny.
Działa to więc tak samo, jak gdybyśmy w zwykłej funkcji wywołali inną, zagnieżdżoną, asynchroniczną.
Kod wewnątrz takiej funkcji byłby oddelegowany do wykonania na później w pętli zdarzeń (jako microtask).
Nieco lepszy obraz sytuacji da nam zamiana forEach()
na map()
i zalogowanie do konsoli takiej mapy.
Okaże się wtedy, że nowa, zmapowana tablica będzie zawierać nierozwiązane obiekty Promise
.
W celu rozwiązania tablicy z obietnicami, możemy użyć Promise.all()
.
Aby wykonać to synchronicznie i nie używać Promise.all().then()
, dodajemy await
przed wywołaniem Promise.all()
i czekamy, aż wszystkie obietnice z tablicy zostaną rozwiązane.
Następnie logując do konsoli store
, mamy już dostęp do wszystkich elementów. Wszystkie obietnice zostały rozwiązane i tym samym wykonane zostały wszystkie wywołania push()
na tablicy store
.
Alternatywnym rozwiązaniem może być wywołanie pętli for
, która w przeciwieństwie do forEach()
nie przyjmuje funkcji callback, a tym samym użycie await
wewnątrz iteracji pętli zostaje wykonane zgodnie z oczekiwaniami.
for (const num of numbers) {
await sleep(1000)
store.push(num)
}
🎢 Plac zabaw
Otwórz edytor w nowym oknie📑 Linki
- Array.prototype.forEach() - JavaScript | MDN
- IIFE - MDN Web Docs Glossary: Definitions of Web-related terms | MDN
- Promise.all() - JavaScript | MDN
- for - JavaScript | MDN
❤️ Podobają Ci się bugi JS?
Podziel się linkiem ze znajomymi:
https://codisity.pl/100-bugow-js