Verstehe, wie die Engine synchronen Code, Microtasks und Macrotasks wirklich einplant.
Diese Lektion in Kodokon öffnenJavaScript führt deinen Code in einem einzigen Thread aus, aber die Event-Loop ist nicht in ECMAScript definiert: Es ist die HTML-Spezifikation (und libuv auf der Node.js-Seite), die beschreibt, wie sie funktioniert. Die Engine verwaltet einen Call-Stack für den gerade laufenden Code, eine Warteschlange von Macrotasks (Timer, I/O, Events) und eine Warteschlange von Microtasks (Promise.prototype.then, queueMicrotask, MutationObserver). Die goldene Regel: Nach jeder Macrotask wird die Microtask-Warteschlange vollständig geleert, bevor die Kontrolle zurückgegeben wird.
console.log("script start");
setTimeout(() => console.log("timeout"), 0);
Promise.resolve()
.then(() => console.log("promise 1"))
.then(() => console.log("promise 2"));
console.log("script end");
// script start, script end,
// promise 1, promise 2, timeoutDas anfängliche Skript ist selbst eine Macrotask: Bis es fertig ist, läuft nichts anderes. Sobald der Call-Stack leer ist, leert die Engine die Microtask-Warteschlange, einschließlich der Microtasks, die während des Leerens hinzugefügt werden. Dieses Detail erklärt, warum zwei verkettete then-Aufrufe vor einem setTimeout(fn, 0) laufen: Jedes then plant eine weitere Microtask ein, und die Kontrolle wird erst zurückgegeben, wenn die Warteschlange leer ist.
setTimeout(() => console.log("macro 1"), 0);
setTimeout(() => console.log("macro 2"), 0);
queueMicrotask(() => {
console.log("micro 1");
queueMicrotask(() => console.log("micro 2"));
});
// micro 1, micro 2, macro 1, macro 2Das Schlüsselwort await baut auf diesem Mechanismus auf: Es pausiert die async-Funktion, gibt die Kontrolle an den Aufrufer zurück und plant dann die Fortsetzung als Microtask ein. Selbst await null löst diese Pause aus, weil der Wert in ein bereits aufgelöstes Promise verpackt wird. Deshalb läuft der Code nach einem await niemals synchron.
async function main() {
console.log("before await");
await null;
console.log("after await");
}
main();
console.log("sync code");
// before await, sync code, after awaitC synchron aus, plant A über setTimeout(fn, 0) und B über Promise.resolve().then ein. In welcher Reihenfolge erscheinen die Buchstaben?await unter der Haube eigentlich?