我认为我们不能讨论将事件循环从堆栈中分离出来,因此:
JS具有三个“堆栈”:
- 所有同步调用的标准堆栈(一个函数调用另一个,等等)
- 所有优先级较高的异步操作(process.nextTick,Promises,Object.observe,MutationObserver)的微任务队列(或作业队列或微任务堆栈)
- 具有较低优先级(setTimeout,setInterval,setImmediate,requestAnimationFrame,I / O,UI呈现)的所有异步操作的宏任务队列(或事件队列,任务队列,宏任务队列)
|=======|
| 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();