Я думаю, що ми не можемо обговорити цикл подій у відриві від стека, тому
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();