I think we can't discuss event loop in separation from the stack, so:
JS has three "stacks":
- standard stack for all synchronous calls (one function calls another, etc)
- microtask queue (or job queue or microtask stack) for all async operations with higher priority (process.nextTick, Promises, Object.observe, MutationObserver)
- macrotask queue (or event queue, task queue, macrotask queue) for all async operations with lower priority (setTimeout, setInterval, setImmediate, requestAnimationFrame, I/O, UI rendering)
|=======|
| macro |
| [...] |
| |
|=======|
| micro |
| [...] |
| |
|=======|
| stack |
| [...] |
| |
|=======|
And event loop works this way:
- execute everything from bottom to top from the stack, and ONLY when the stack is empty, check what is going on in queues above
- check micro stack and execute everything there (if required) with help of stack, one micro-task after another until the microtask queue is empty or don't require any execution and ONLY then check the macro stack
- check macro stack and execute everything there (if required) with help of the stack
Micro stack won't be touched if the stack isn't empty. The macro stack won't be touched if the micro stack isn't empty OR does not require any execution.
To sum up: microtask queue is almost the same as macrotask queue but those tasks (process.nextTick, Promises, Object.observe, MutationObserver) have higher priority than macrotasks.
Micro is like macro but with higher priority.
Here you have "ultimate" code for understanding everything.
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
*/