Node.js Event Loop各阶段讲解

2020-06-17 05:44:04易采站长站整理

Event Loop阶段描述图

timers

timer阶段处理setTimeout于setInterval回调,开始处理的时机与poll阶段有关联。

pending callbacks

该阶段执行某些系统操作的回调,比如TCP套接字在连接时收到ECONNREFUSED。

网上有一些将该阶段称为I/O callbacks的文章都是过时错误的,具体可以移步Node.js官方库下面的这个issue: #1118。

idle, prepare

内部使用,忽略。

poll

poll是一个核心阶段,等新I/O事件的触发,以及执行I/O相关回调。Node.js中出现异步的绝大部分情况都是I/O操作,它们的回调基本都在这个阶段被执行。

poll阶段主要做两件事:

计算需要为新的的I/O事件等待多久

当进入poll阶段,如果队列为空且不存在setImmediate与就绪的timer,Node.js会在这里block一定的时间等待新的I/O事件到来,然后立即执行其回调。这种情况具体block等待多久是不具体的,但如果在block一定时间后仍没有新到达的I/O事件,可以肯定循环依旧会进入check阶段或者回到timer阶段。

处理该阶段队列中的事件

当进入poll阶段,如果队列不为空且没有就绪的timer,Node.js会在这里执行队列中的callback直到队列为空或者执行的callback数达到系统设定的某个值。随后Node.js检查是否存在预设的setImmediate,存在话就进入check阶段,否则开始检查timer就绪情况选择回到timer阶段或者进入check阶段。

对于poll阶段,通过阅读官方的文档有些细节也没弄清楚,用伪代码表示出来:


enter pool phase:
if (has timer scheduled) {
// 官方没有提到这种情况会做什么
}
else {
if (isEmpty(queue)) {
if (has(setImmediate)) {
// 进入check阶段
}
else if (!isEmpty(timer)) {
// 回到timer阶段
}
else {
// 等待新的I/O事件
// 新的I/O事件触发回调立即执行,执行完成之后的逻辑不清楚
}
// 目前看来只有存在setImmediate时才会进入check阶段,这肯定不合理
}
if (!isEmpty(queue)) {
let result = execute(queue);
if (result === 'queue is empty') {
// 官方没讲后续逻辑
// 猜测是回到队列为空的处理逻辑中
}
if (result === 'reached hard limit') {
// 官方没有解释这里的后续逻辑
// 也许与queue is empty一样对待
}
}
}

疑惑重点是从poll阶段出来的时机以及去向不是非常明确,但以我目前的水平和精力只能到此为止。