Я думаю, что мы не можем обсуждать цикл обработки событий при отделении от стека, поэтому:
JS имеет три «стека»:
- стандартный стек для всех синхронных вызовов (одна функция вызывает другую и т. д.)
- очередь микрозадач (или очередь заданий, или стек микрозадач) для всех асинхронных операций с более высоким приоритетом (process.nextTick, Promises, Object.observe, MutationObserver)
- очередь макрозадач (или очередь событий, очередь задач, очередь макрозадач) для всех асинхронных операций с более низким приоритетом (setTimeout, setInterval, setImmediate, requestAnimationFrame, I / O, рендеринг пользовательского интерфейса)
|=======|
| macro |
| [...] |
| |
|=======|
| micro |
| [...] |
| |
|=======|
| stack |
| [...] |
| |
|=======|
И цикл обработки событий работает следующим образом:
- выполнять все снизу вверх из стека, и ТОЛЬКО когда стек пуст, проверять, что происходит в очередях выше
- проверить микростек и выполнить все там (при необходимости) с помощью стека, одну микрозадачу за другой, пока очередь микрозадач не станет пустой или не потребует выполнения, и ТОЛЬКО затем проверьте стек макросов
- проверить стек макросов и выполнить все там (если требуется) с помощью стека
Стек Mico не будет трогаться, если стек не пуст. Макропакет не будет сенсорным, если микропогрузка не пуста ИЛИ не требует выполнения.
Подводя итог: очередь микрозадач почти такая же, как очередь макрозадач, но эти задачи (process.nextTick, Promises, Object.observe, MutationObserver) имеют более высокий приоритет, чем макрозадачи.
Микро как макро, но с более высоким приоритетом.
Вот вам и «окончательный» код для понимания всего.
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();