JavaScript-Event-Loop, Microtasks und Macrotasks
JavaScript ist eine leistungsstarke Sprache, die häufig in der Webentwicklung verwendet wird, und eines ihrer Kernkonzepte ist, wie sie asynchrone Operationen verarbeitet. Um dieses Konzept für Anfänger verständlicher zu machen, sehen wir uns den Event Loop sowie die Rollen von Microtasks und Macrotasks an, ergänzt durch einfache Beispiele, die zeigen, wie JavaScript verschiedene Operationen verwaltet.
Vereinfachte Übersicht über den Event Loop
Der Event Loop ist ein Mechanismus, den JavaScript verwendet, um die Ausführung von Code, Ereignissen und Nachrichten effizient zu handhaben. So lässt er sich leicht veranschaulichen:
- Stack: Hier beginnt die Ausführung Ihres JavaScript-Codes, von oben nach unten, wie beim Stapeln von Blöcken.
- Heap: Stellen Sie sich dies als den Speicherbereich für Objekte vor, die Ihr Code erstellt.
- Queue: JavaScript verwendet tatsächlich zwei separate Queues: eine Macrotask-Queue (für Timer, UI-Ereignisse und I/O) und eine Microtask-Queue (für Promises und
queueMicrotask).
Der Event Loop prüft fortlaufend den Stack, um zu sehen, ob etwas ausgeführt werden muss. Wenn der Stack leer ist, prüft er zuerst die Microtask-Queue. Sobald die Microtask-Queue leer ist, sieht er sich die Macrotask-Queue an, um zu prüfen, ob dort wartende Aufgaben zur Ausführung vorhanden sind. Dieser Zyklus ermöglicht es JavaScript, Aufgaben wie UI-Aktualisierungen, Benutzerinteraktionen oder das Abrufen von Daten im Hintergrund auszuführen, ohne den Hauptthread zu blockieren.
Hier ist ein einfaches Beispiel, das erklärt, wie der JavaScript-Event-Loop funktioniert, insbesondere mit Fokus auf die Verarbeitung asynchroner Ereignisse mit setTimeout:
In diesem Beispiel:
console.log('Start');wird zuerst ausgeführt und gibt "Start" in der Konsole aus.setTimeoutplant eine Callback-Funktion, die nach 1000 Millisekunden (1 Sekunde) ausgeführt wird. Es blockiert jedoch nicht die Ausführung des nachfolgenden Codes.console.log('End');wird unmittelbar nach dem Planen des Timeouts ausgeführt und gibt "End" in der Konsole aus.- Nachdem der Hauptthread frei ist und die 1-Sekunden-Verzögerung abgelaufen ist, prüft der Event Loop zuerst die Microtask-Queue. Wenn sie leer ist, wechselt er zur Macrotask-Queue, findet den Callback von
setTimeoutund führt ihn aus, wodurch "Timeout Callback" in der Konsole ausgegeben wird.
Diese Abfolge zeigt effektiv, wie der JavaScript-Event-Loop Aufgaben verarbeitet und wie er die Task-Queue verwendet, um asynchrone Ereignisse wie Timeouts zu verwalten. Der setTimeout-Callback ist ein Beispiel für eine Macrotask, die nach dem aktuell ausgeführten Skript und allen anderen ausstehenden Aufgaben verarbeitet wird. Dadurch wird sichergestellt, dass der synchrone Code sofort ausgeführt wird, ohne auf den asynchronen Code zu warten (wie I/O-Operationen oder Timer), was die Anwendung reaktionsfähig hält.
Microtasks vs. Macrotasks
Was sind Macrotasks?
Macrotasks sind größere Aufgabenblöcke, zu denen Dinge wie die folgenden gehören:
setTimeout: Verzögert die Ausführung eines Codeabschnitts, bis mindestens die von Ihnen angegebene Zeit vergangen ist.setInterval: Führt einen Codeabschnitt nach jedem angegebenen Intervall fortlaufend aus.- Ereignisse und I/O-Operationen: Zum Beispiel das Klicken auf eine Schaltfläche oder das Laden von Daten aus einer externen Quelle.
Jede Macrotask wird abgeschlossen, bevor zur nächsten übergegangen wird.
Was sind Microtasks?
Microtasks sind kleine Aufgaben, die ohne Unterbrechung erledigt werden müssen. Dazu gehören:
- Promise-Auflösungen: Aktionen, die Sie versprechen auszuführen, wenn etwas anderes erledigt ist.
queueMicrotask-Funktion: Fügt Microtasks direkt hinzu.
Microtasks werden schneller und häufiger verarbeitet als Macrotasks. Sie werden nach jeder Macrotask und bevor die JavaScript-Engine die nächste Macrotask übernimmt, verarbeitet.
Praxisnahe Codebeispiele
Beispiel 1: setTimeout als Macrotask verwenden
Stellen Sie sich vor, Sie möchten nach 2 Sekunden eine Nachricht auf einer Webseite anzeigen.
Erklärung: Dieser Code richtet einen Timer ein, der 2 Sekunden wartet, bevor er ausgeführt wird. Anschließend ändert er den Text eines Elements auf der Seite (erfordert eine Browser-Umgebung). Dies ist eine Macrotask, da sie unabhängig vom Hauptprogrammablauf ausgeführt werden soll.
Beispiel 2: Promises als Microtasks verwenden
Angenommen, Sie möchten direkt nach einer kurzen Aufgabe, etwa einer Statusaktualisierung, eine Nachricht protokollieren.
Erklärung: Dieser Code erstellt ein Promise, das sofort aufgelöst wird, und führt dann den Code innerhalb von .then() sofort aus, sobald der Stack leer ist. Dies ist eine Microtask, weil es sich um eine kleine Aufgabe handelt, die direkt nach dem aktuellen Code ausgeführt werden muss.
Mehr über die Priorität von Micro- und Macrotasks
In JavaScript werden, wie wir gelernt haben, Aufgaben innerhalb des Event Loops entweder als Microtasks oder Macrotasks kategorisiert, jeweils mit einer bestimmten Priorität. Microtasks umfassen Operationen wie die Verarbeitung von Promises und haben immer eine höhere Priorität. Das bedeutet, dass nach dem Abschluss des aktuellen Skripts die JavaScript-Engine alle ausstehenden Microtasks verarbeitet, bevor sie mit Macrotasks wie Timeouts oder Event-Handlern beginnt.
Hier ist ein einfaches Beispiel, um dies in Aktion zu sehen:
Erwartete Ausgabe:
Start
End
Promise 1
Promise 2
Timeout 1
Timeout 2Diese Abfolge zeigt, wie Microtasks (Promise-Auflösungen) unmittelbar nach synchronem Code ausgeführt werden, sogar noch vor Macrotasks, die für denselben Zeitpunkt geplant sind. Diese Priorisierung stellt sicher, dass wichtige Aufgaben wie das Aktualisieren von Daten so schnell wie möglich abgeschlossen werden.
Fazit
Das Verständnis des Event Loops sowie von Microtasks und Macrotasks kann Ihre Fähigkeit, effiziente JavaScript zu schreiben, erheblich verbessern. Wenn Sie wissen, wie und wann JavaScript Ihren Code ausführt, können Sie reaktionsfähigere und effizientere Anwendungen erstellen. Die wichtigste Erkenntnis ist, Macrotasks für große, weniger dringende Aufgaben und Microtasks für kleine, sofortige Aufgaben zu verwenden. Dieser Leitfaden sollte Ihnen helfen, die Grundlagen zu verstehen und diese Konzepte in Ihren eigenen Projekten anzuwenden!
Practice
In JavaScript, what happens when a promise resolves and there is a `.then()` handler attached?