Penso che non possiamo discutere il loop degli eventi in separazione dallo stack, quindi:
JS ha tre "pile":
- stack standard per tutte le chiamate sincrone (una funzione chiama un'altra, ecc.)
- coda microtask (o coda lavori o stack microtask) per tutte le operazioni asincrone con priorità più alta (process.nextTick, Promises, Object.observe, MutationObserver)
- coda macrotask (o coda eventi, coda attività, coda macrotask) per tutte le operazioni asincrone con priorità inferiore (setTimeout, setInterval, setImmediate, requestAnimationFrame, I / O, UI rendering)
|=======|
| macro |
| [...] |
| |
|=======|
| micro |
| [...] |
| |
|=======|
| stack |
| [...] |
| |
|=======|
E il ciclo degli eventi funziona in questo modo:
- esegui tutto dal basso verso l'alto dallo stack e SOLO quando lo stack è vuoto, controlla cosa sta succedendo nelle code sopra
- controlla il micro stack ed esegui tutto lì (se richiesto) con l'aiuto dello stack, un micro task dopo l'altro fino a quando la coda microtask è vuota o non richiede alcuna esecuzione e SOLO quindi controlla lo stack macro
- controlla lo stack di macro ed esegui tutto lì (se richiesto) con l'aiuto dello stack
Lo stack Mico non verrà toccato se lo stack non è vuoto. Lo stack macro non verrà toccato se il micro stack non è vuoto O non richiede alcuna esecuzione.
Per riassumere: la coda microtask è quasi uguale alla coda macrotask ma quelle attività (process.nextTick, Promises, Object.observe, MutationObserver) hanno una priorità maggiore rispetto ai macrotask.
Micro è come macro ma con priorità più alta.
Qui hai il codice "definitivo" per capire tutto.
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();