Acho que não podemos discutir o loop de eventos na separação da pilha, então:
JS tem três "pilhas":
- pilha padrão para todas as chamadas síncronas (uma função chama outra etc.)
- fila de microtask (ou fila de trabalhos ou pilha de microtask) para todas as operações assíncronas com prioridade mais alta (process.nextTick, Promises, Object.observe, MutationObserver)
- fila de macrotask (ou fila de eventos, fila de tarefas, fila de macrotask) para todas as operações assíncronas com prioridade mais baixa (setTimeout, setInterval, setImmediate, requestAnimationFrame, E / S, renderização da interface do usuário)
|=======|
| macro |
| [...] |
| |
|=======|
| micro |
| [...] |
| |
|=======|
| stack |
| [...] |
| |
|=======|
E o loop de eventos funciona desta maneira:
- execute tudo de baixo para cima da pilha e SOMENTE quando a pilha estiver vazia, verifique o que está acontecendo nas filas acima
- verifique a micro pilha e execute tudo o que estiver lá (se necessário) com a ajuda da pilha, uma micro tarefa após a outra até que a fila de microtask esteja vazia ou não exija nenhuma execução e SOMENTE verifique a pilha de macro
- verifique a pilha de macros e execute tudo o que estiver lá (se necessário) com a ajuda da pilha
A pilha do Mico não será tocada se a pilha não estiver vazia. A pilha de macros não será tocada se a micro pilha não estiver vazia OU não exigir execução.
Resumindo: a fila de microtask é quase a mesma da fila de macrotask, mas essas tarefas (process.nextTick, Promises, Object.observe, MutationObserver) têm prioridade mais alta que as macrotasks.
Micro é como macro, mas com maior prioridade.
Aqui você tem um código "definitivo" para entender tudo.
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();