今天小编就为你们分享一篇关于Node.js Event Loop各阶段讲解,写的十分的全面细致,具备必定的参考价值,对此有须要的朋友能够参考学习下。若有不足之处,欢迎批评指正。前端
Event Loop阶段描述图node
timersgit
timer阶段处理setTimeout于setInterval回调,开始处理的时机与poll阶段有关联。github
pending callbacksbash
该阶段执行某些系统操做的回调,好比TCP套接字在链接时收到ECONNREFUSED。异步
网上有一些将该阶段称为I/O callbacks的文章都是过期错误的,具体能够移步Node.js官方库下面的这个issue: #1118。socket
idle, prepareoop
内部使用,忽略。学习
poll优化
poll是一个核心阶段,等新I/O事件的触发,以及执行I/O相关回调。Node.js中出现异步的绝大部分状况都是I/O操做,它们的回调基本都在这个阶段被执行。
poll阶段主要作两件事:
当进入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阶段,这确定不合理
}//在此我向你们推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提高思惟能力
if (!isEmpty(queue)) {
let result = execute(queue);
if (result === 'queue is empty') {
// 官方没讲后续逻辑
// 猜想是回到队列为空的处理逻辑中
}
if (result === 'reached hard limit') {
// 官方没有解释这里的后续逻辑
// 也许与queue is empty同样对待
}
}
}//在此我向你们推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提高思惟能力
复制代码
疑惑重点是从poll阶段出来的时机以及去向不是很是明确,但以我目前的水平和精力只能到此为止。
check
当poll阶段执行完成会进入到check阶段执行,该阶段的执行内容是全部setImmediate回调。
close callbacks
socket的异常关闭,'close'事件的回调会在该阶段执行。
process.nextTick
process.nextTick常常被用来作异步调用,但它并不属于事件循环的内容,process.nextTick中的回调被放在nextTickQueue中等待“当前操做”完成后被当即处理,与事件循环中的阶段没有联系,当前操做的原文定义是:“An operation is defined as a transition from the underlying C/C++ handler, and handling the JavaScript that needs to be executed.”,指的是在一段Javascript代码执行完切换到C/C++层时会处理nextTickQueue。
在此我向你们推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提高思惟能力
文章提到了一个特例是Deduplication,这是Node.js内部一个优化特性,当在timer和check阶段,同时有多个须要执行的回调时,切换只会发生一次,因此nextTick回调执行在这种状况下看似有所延后。 代码示例:
setImmediate(() => {
console.log('1');
process.nextTick(() => console.log('2'));
});
setImmediate(() => {
console.log('3');
process.nextTick(() => console.log('4'));
});
复制代码
存在两个setImmediate,进入check阶段后须要在执行全部setImmediate的回调代码后才会产生切换,从而执行nextTick回调,所以上面代码的运行结果是:“1 3 2 4”,除上述场景外,nextTick都会先于setImmediate执行。
总结
由于Node.js的Event Loop我看了有那么二、3回,但常常忘,因此此次记录下来,作个备忘。因为太多知识容易忘记,又发现写文章的一个优势:“帮助记忆便于复习”。
结语
感谢您的观看,若有不足之处,欢迎批评指正。