Nodejs中的事件循环机制

在浏览器事件循环中,我们了解到javascript在浏览器中的事件循环机制,其是根据html5定义的规范来实现的

而在nodejs中,事件循环是基于libuv实现,libuv是一个多平台的专注于异步IO的库,如下图

image.png

上图EVENT_QUEUE给人看起来只有一个队列,但是EventLoop存在6个阶段,每个阶段都有对应的一个先进先出的回调队列

流程

image.png
  • timers阶段:这个阶段执行timer(setTimeout,setInterval)的回调
  • 定时器检测阶段(timers):本阶段执行timer的回调,即setTimeout,setInterval里面的回调函数
  • I/O 事件回调阶段:执行延迟到下一个循环迭代的I/O回调,即上一轮循环中未被执行的一些I/O 回调
  • 限制阶段:仅供系统内部使用
  • 轮训阶段poll:检索新的I/O事件,执行与I/O相关的回调,几乎所有的情况下,除了关于的回调函数,那些计时器和setImmediate()调度之外,其余情况node将在适当的时候在此阻塞
  • 检查阶段:setImmediate()回调函数在这里执行
  • 关闭事件回调阶段:一些关闭的回调函数,如:socket.on('close',……)

每个阶段对应一个队列,当事件循环进入某个阶段时,将会在该阶段内执行回调,直到队列好近或者回调的最大数量已执行,那么将进入下一个阶段

除了上述6个阶段,还存在process.nextTick,其部署事件循环的任何一个阶段,属于该阶段与下阶段之间的过度,即本阶段执行结束,进入下一个阶段前,所要执行的回调,类似插队

image.png

在Nodejs中,同样存在宏任务和微任务,与浏览器中的时间循环相似

微任务对应的有:

  • next tick queue:process.nextTick
  • other queue: Promise的then回调,queueMicrotask

宏任务对应的有:

  • timer queue:setTimeout,setInterval
  • poll queue: IO事件
  • check queue: setImmediate
  • close queue:close事件

其执行顺序为:

  • next tick microtask queue
  • other microtask queue
  • timer queue
  • poll queue
  • check queue
  • close queue
async function async1() {
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}

async function async2(){
    console.log("async2")
}

console.log("script start")

setTimeout(()=>{
    console.log("setTimout0")
},0)

setTimeout(function () {
    console.log('setTimeout2')
}, 300)

setImmediate(() => console.log('setImmediate'));

process.nextTick(() => console.log('nextTick1'));

async1();

process.nextTick(() => console.log('nextTick2'));

new Promise(function (resolve) {
    console.log('promise1')
    resolve();
    console.log('promise2')
}).then(function () {
    console.log('promise3')
})

console.log('script end')

分析过程:

  • 先找到同步任务,输出script start
  • 遇到第一个setTimout将里面的函数放入timer队列中
  • 遇到第二个setTimout,300ms后将里面的回调函数放到timer队列中
  • 遇到第一个setImmediate,将里面的回调函数放到check队列中
  • 遇到第一个nextTick,将里面的回调函数放到本轮同步任务执行完毕后执行
  • 执行async1 函数,输出async1 start
  • 执行async2 函数,输出async2 ,async2后面输出async 1 end进入微任务,等待下一轮事件循环
  • 遇到第二个,将里面的回调函数放到本轮同步任务执行完毕后执行
  • 遇到new Promise,执行里面的立即执行函数,出书promise1,promise2
  • then里面的回调函数进入到微任务队列
  • 遇到同步任务,输出script end
  • 执行下一轮回调函数,先依次输出nextTick函数,分别是nextTick1,nextTick2
  • 然后执行微任务队列,依次输出async1 end,promise3
  • 执行timer队列,依次输出setTimeout0
  • 接着执行check队列,依次输出setImmedate
  • 300ms后,timer队列存在任务,执行输出setTimeout2
script start
async1 start
async2
promise1
promise2
script end
nextTick1
nextTick2
async1 end
promise3
setTimeout0
setImmediate
setTimeout2
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

友情链接更多精彩内容