JavaScript — to język programowania o jednolitym charakterze, ale potrafi obsługiwać operacje asynchroniczne. Jest to możliwe dzięki Event Loop — mechanizmowi, który pozwala JavaScriptowi wykonywać kod bez blokowania głównego wątku. W tym wpisie przyjrzymy się, jak dokładnie działa Event Loop, dlaczego jest ważny i jak prawidłowo wykorzystać jego cechy.
Podstawy działania Event Loop
W podstawach działania Event Loop leżą trzy główne składniki:
- Call Stack (stos wywołań) — miejsce, gdzie wykonywane są funkcje synchronizacyjne.
- Task Queue (kolejka zadań) — lista callbacków, które czekają na swoją kolej do wykonania.
- Microtask Queue (kolejka mikrozadań) — kolejka dla Promise i innych mikrozadań.
Przyjrzyjmy się przykładowi:
console.log("Początek");
setTimeout(() => {
console.log("setTimeout");
}, 0);
Promise.resolve().then(() => {
console.log("Promise");
});
console.log("Koniec");
Oczekiwany porządek wykonania:
-
console.log("Początek")— wyświetlane od razu. -
setTimeoutodkłada wykonanie callbacka w Task Queue. -
Promise.resolve().then(...)dodaje callback do Microtask Queue. -
console.log("Koniec")— wyświetlane od razu. - Po zakończeniu kodu synchronizacyjnego Event Loop sprawdza Microtask Queue — wykonywane jest
console.log("Promise"). - Dopiero po tym wykonywany jest callback z Task Queue —
console.log("setTimeout").
Wynik w konsoli będzie:
Początek
Koniec
Promise
setTimeout
Dlaczego setTimeout(..., 0) nie wykonuje się natychmiast?
setTimeout(..., 0) nie oznacza, że funkcja wykona się od razu. Dodaje callback do Task Queue, który jest przetwarzany dopiero po wykonaniu wszystkich mikrozadań.
Przykład, gdzie to dobrze widać:
setTimeout(() => console.log("setTimeout"), 0);
for (let i = 0; i < 1e9; i ++) {} // Blokujemy główny wątek
console.log("Koniec pętli");
Tu setTimeout opóźnia się, aż pętla się zakończy, nawet jeśli ustawione jest 0 milisekund.
Użycie queueMicrotask
Jeśli potrzebujesz wykonać kod wcześniej niż setTimeout, możesz skorzystać z queueMicrotask:
queueMicrotask(() => console.log("Mikrozadanie"));
console.log("Kod główny");
Wynik:
Kod główny
Mikrozadanie
```