Node
中的Event loop
和浏览器中的不相同。Node
的Event loop
分为6
个阶段,它们会按照顺序反复运行
timer
timers
阶段会执行setTimeout
和setInterval
- 一个
timer
指定的时间并不是准确时间,而是在达到这个时间后尽快执行回调,可能会因为系统正在执行别的事务而延迟
I/O
I/O
阶段会执行除了close
事件,定时器和setImmediate
的回调
poll
-
poll
阶段很重要,这一阶段中,系统会做两件事情执行到点的定时器
执行poll
队列中的事件 -
并且当
poll
中没有定时器的情况下,会发现以下两件事情如果
poll
队列不为空,会遍历回调队列并同步执行,直到队列为空或者系统限制
如果poll
队列为空,会有两件事发生
如果有setImmediate
需要执行,poll
阶段会停止并且进入到check
阶段执行setImmediate
如果没有setImmediate
需要执行,会等待回调被加入到队列中并立即执行回调
如果有别的定时器需要被执行,会回到timer
阶段执行回调。
check
check
阶段执行setImmediate
close callbacks
close callbacks
阶段执行close
事件- 并且在
Node
中,有些情况下的定时器执行顺序是随机的
setTimeout(() => {
console.log('setTimeout');
}, 0);
setImmediate(() => {
console.log('setImmediate');
})
// 这里可能会输出 setTimeout,setImmediate
// 可能也会相反的输出,这取决于性能
// 因为可能进入 event loop 用了不到 1 毫秒,这时候会执行 setImmediate
// 否则会执行 setTimeout
上面介绍的都是
macrotask
的执行情况,microtask
会在以上每个阶段完成后立即执行
setTimeout(()=>{
console.log('timer1')
Promise.resolve().then(function() {
console.log('promise1')
})
}, 0)
setTimeout(()=>{
console.log('timer2')
Promise.resolve().then(function() {
console.log('promise2')
})
}, 0)
// 以上代码在浏览器和 node 中打印情况是不同的
// 浏览器中一定打印 timer1, promise1, timer2, promise2
// node 中可能打印 timer1, timer2, promise1, promise2
// 也可能打印 timer1, promise1, timer2, promise2
Node
中的process.nextTick
会先于其他microtask
执行
setTimeout(() => {
console.log("timer1");
Promise.resolve().then(function() {
console.log("promise1");
});
}, 0);
process.nextTick(() => {
console.log("nextTick");
});
// nextTick, timer1, promise1
对于
microtask
来说,它会在以上每个阶段完成前清空microtask
队列,下图中的Tick
就代表了microtask