JavaScript — ist eine Programmiersprache mit einer einsträngigen Natur, aber sie kann auch asynchrone Operationen verarbeiten. Dies ist dank des Event Loop möglich — einem Mechanismus, der es JavaScript ermöglicht, Code auszuführen, ohne den Hauptthread zu blockieren. In diesem Beitrag werden wir untersuchen, wie der Event Loop funktioniert, warum er wichtig ist und wie man seine Besonderheiten richtig nutzt.
Grundlagen der Funktionsweise des Event Loop
Der Event Loop basiert auf drei Hauptkomponenten:
- Call Stack (Aufrufstapel) — der Ort, an dem synchrone Funktionen ausgeführt werden.
- Task Queue (Aufgabenwarteschlange) — eine Liste von Callbacks, die auf ihre Ausführung warten.
- Microtask Queue (Mikroaufgabenwarteschlange) — eine Warteschlange für Promises und andere Mikroaufgaben.
Betrachten wir ein Beispiel:
console.log("Anfang");
setTimeout(() => {
console.log("setTimeout");
}, 0);
Promise.resolve().then(() => {
console.log("Promise");
});
console.log("Ende");
Die erwartete Ausführungsreihenfolge:
-
console.log("Anfang")— wird sofort ausgegeben. -
setTimeoutverzögert die Ausführung des Callbacks in die Aufgabenwarteschlange. -
Promise.resolve().then(...)fügt den Callback zur Mikroaufgabenwarteschlange hinzu. -
console.log("Ende")— wird sofort ausgegeben. - Nach Abschluss des synchronen Codes überprüft der Event Loop die Mikroaufgabenwarteschlange —
console.log("Promise")wird ausgeführt. - Erst danach wird der Callback aus der Aufgabenwarteschlange ausgeführt —
console.log("setTimeout").
Das Ergebnis in der Konsole wird sein:
Anfang
Ende
Promise
setTimeout
Warum wird setTimeout(..., 0) nicht sofort ausgeführt?
setTimeout(..., 0) bedeutet nicht, dass die Funktion sofort ausgeführt wird. Es fügt den Callback zur Aufgabenwarteschlange hinzu, die erst nach der Ausführung aller Mikroaufgaben verarbeitet wird.
Ein Beispiel, in dem dies gut zu sehen ist:
setTimeout(() => console.log("setTimeout"), 0);
for (let i = 0; i < 1e9; i++) {} // Blockieren des Hauptthreads
console.log("Ende der Schleife");
Hier wird setTimeout verzögert, bis die Schleife abgeschlossen ist, selbst wenn 0 Millisekunden angegeben sind.
Verwendung von queueMicrotask
Wenn Sie Code früher ausführen möchten als mit setTimeout, können Sie queueMicrotask verwenden:
queueMicrotask(() => console.log("Mikroaufgabe"));
console.log("Hauptcode");
Das Ergebnis:
Hauptcode
Mikroaufgabe