Ich denke, wir können die Ereignisschleife nicht getrennt vom Stapel diskutieren, also:
JS hat drei "Stapel":
- Standardstapel für alle synchronen Aufrufe (eine Funktion ruft eine andere auf usw.)
- Mikrotask-Warteschlange (oder Job-Warteschlange oder Mikrotask-Stapel) für alle asynchronen Vorgänge mit höherer Priorität (process.nextTick, Promises, Object.observe, MutationObserver)
- Macrotask-Warteschlange (oder Ereigniswarteschlange, Task-Warteschlange, Macrotask-Warteschlange) für alle asynchronen Vorgänge mit niedrigerer Priorität (setTimeout, setInterval, setImmediate, requestAnimationFrame, E / A, UI-Rendering)
|=======|
| macro |
| [...] |
| |
|=======|
| micro |
| [...] |
| |
|=======|
| stack |
| [...] |
| |
|=======|
Und die Ereignisschleife funktioniert folgendermaßen:
- Führen Sie alles von unten nach oben vom Stapel aus aus. Überprüfen Sie NUR, wenn der Stapel leer ist, was in den obigen Warteschlangen vor sich geht
- Überprüfen Sie den Mikrostapel und führen Sie dort (falls erforderlich) alles mit Hilfe des Stapels aus, eine Mikroaufgabe nach der anderen, bis die Mikrotask-Warteschlange leer ist oder keine Ausführung erforderlich ist, und überprüfen Sie NUR dann den Makrostapel
- Überprüfen Sie den Makro-Stack und führen Sie dort (falls erforderlich) alles mit Hilfe des Stacks aus
Der Mico-Stack wird nicht berührt, wenn der Stack nicht leer ist. Der Makrostapel wird nicht berührt, wenn der Mikrostapel nicht leer ist ODER keine Ausführung erfordert.
Zusammenfassend lässt sich sagen: Die Mikrotask-Warteschlange entspricht fast der Makrotask-Warteschlange, aber diese Aufgaben (process.nextTick, Promises, Object.observe, MutationObserver) haben eine höhere Priorität als Makrotask.
Mikro ist wie Makro, aber mit höherer Priorität.
Hier haben Sie "ultimativen" Code, um alles zu verstehen.
console.log('stack [1]');
setTimeout(() => console.log("macro [2]"), 0);
setTimeout(() => console.log("macro [3]"), 1);
const p = Promise.resolve();
for(let i = 0; i < 3; i++) p.then(() => {
setTimeout(() => {
console.log('stack [4]')
setTimeout(() => console.log("macro [5]"), 0);
p.then(() => console.log('micro [6]'));
}, 0);
console.log("stack [7]");
});
console.log("macro [8]");
/* Result:
stack [1]
macro [8]
stack [7], stack [7], stack [7]
macro [2]
macro [3]
stack [4]
micro [6]
stack [4]
micro [6]
stack [4]
micro [6]
macro [5], macro [5], macro [5]
--------------------
but in node in versions < 11 (older versions) you will get something different
stack [1]
macro [8]
stack [7], stack [7], stack [7]
macro [2]
macro [3]
stack [4], stack [4], stack [4]
micro [6], micro [6], micro [6]
macro [5], macro [5], macro [5]
more info: https://blog.insiderattack.net/new-changes-to-timers-and-microtasks-from-node-v11-0-0-and-above-68d112743eb3
*/
while (task = todo.shift()) task();