Creo que no podemos discutir el bucle de eventos en separación de la pila, así que:
JS tiene tres "pilas":
- pila estándar para todas las llamadas síncronas (una función llama a otra, etc.)
- cola de microtask (o cola de trabajos o pila de microtask) para todas las operaciones asíncronas con mayor prioridad (process.nextTick, Promises, Object.observe, MutationObserver)
- cola de macrotask (o cola de eventos, cola de tareas, cola de macrotask) para todas las operaciones asincrónicas con menor prioridad (setTimeout, setInterval, setImmediate, requestAnimationFrame, I / O, UI rendering)
|=======|
| macro |
| [...] |
| |
|=======|
| micro |
| [...] |
| |
|=======|
| stack |
| [...] |
| |
|=======|
Y el bucle de eventos funciona de esta manera:
- ejecute todo de abajo hacia arriba desde la pila, y SOLO cuando la pila esté vacía, verifique lo que sucede en las colas de arriba
- compruebe la micro pila y ejecute todo lo que esté allí (si es necesario) con la ayuda de la pila, una micro tarea tras otra hasta que la cola de microtask esté vacía o no requiera ejecución y SOLO luego verifique la macro pila
- compruebe la pila de macros y ejecute todo allí (si es necesario) con la ayuda de la pila
La pila Mico no se tocará si la pila no está vacía. La pila de macros no se tocará si la micro pila no está vacía O no requiere ninguna ejecución.
En resumen: la cola de microtask es casi lo mismo que la cola de macrotask, pero esas tareas (process.nextTick, Promises, Object.observe, MutationObserver) tienen mayor prioridad que las macrotasks.
Micro es como macro pero con mayor prioridad.
Aquí tienes el código "definitivo" para entender todo.
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();