一、Node事件循环的几个阶段
与浏览器环境下的事件循环不同,Node环境下的事件循环分为几个阶段:
- timers:这个阶段执行定时器(setTimeout和setInterval)的callback。
- pending I/O callbacks:这个阶段会执行一些系统操作的回调,比如TCP错误;注意:虽然名字带I/O,但是I/O事件的回调并不在这个阶段。
- idle、prepare:这两个阶段仅供Node内部使用。
- poll:也称轮询阶段,I/O事件将在这个阶段执行。node将会在此处阻塞。
- check:执行setImmediate的回调。。
- close:执行一些关闭的回调函数,比如socket.on(‘close’, …)。
每个阶段都有一个FIFO队列来执行回调。当事件循环进入一个阶段,会把该阶段的回调执行完或者达到最大回调数,才会移动到下一个阶段。
比较重要的是这几个阶段:timers、poll、check。
- timers阶段:timers阶段的每个timer都会给定一个下限时间,也就是setTimeout(callback,time)里的time,这个时间并不是说在time后就一定会执行callback,而是time后把callback放进timers队列中,具体何时执行还得看事件循环到了哪个阶段以及该callback在timers队列中的位置。
- poll阶段:轮询阶段有两个主要任务,分别是检查有无已超时的timer和执行poll队列中的任务。
- 依次执行poll队列中的任务,直到将队列中的任务执行完,或是达到最高回调数。
- 如果有已超时的timer,则事件循环将跳转到timers阶段去执行超时timer的callback。
- 如果check阶段有回调(setImmediate)在等待,则到达check阶段执行check队列中的回调,如果没有则事件循环会一直阻塞在这个阶段,等待新的I/O事件加入到poll队列中。
- check阶段:poll阶段如果空闲,且有待执行的setImmediate的callback,就会跳转到check阶段。
二、宏任务和微任务
在Node中,微任务指的是不在事件循环中的任务,Node环境下只有process.nextTick和Promise的callback这两种微任务,且nextTick的优先级是比Promise的callBack要高的。
那么微任务会在什么时候执行呢?
- Node V11之前
微任务会在一个阶段结束与进入下一个阶段之间进行,也就是说微任务只会在阶段与阶段之间处理,这一点与浏览器是很不一样的(浏览器中,在执行宏任务的过程中遇到微任务就会立即执行微任务)。 - Node V11之后
微任务会在各个独立的宏任务之间进行,与浏览器保持一致。
三、总结
前面的阶段都按顺序执行,
进入到poll阶段后:
参考:
- https://juejin.cn/post/6844904137662922760#comment
- https://juejin.cn/post/6844904019454853128
- https://juejin.cn/post/6844904100195205133