Nodejs中的事件循环(event loop)

183 阅读4分钟
  • 首先,node当中的event loop和浏览器中的是不相同
  • nodejsevent loop是基于libuv,而浏览器的event loop则在html5的规范中明确定义
  • libuv真正地实现了nodejs的event loop(有源码),而html5只是提供了event loop的模型,留给各大浏览器去自己实现源码
  • Node当中的Event loop分为6个阶段,每一个阶段都有自己的队列,他们会按照顺序反复运行

image.png

  • timers阶段
    • 1.检查timer队列中是否有到期的timer回调,如果有,按照timerID升序执行
    • 2.检查timer队列中是否有process.nextTick任务,如果有,全部执行
    • 3.检查timer队列中是否有microtask,如果有,全部执行
    • 4.退出该阶段
    • 执行过程:查看 到期的Timer回调 => process.nextTick => microTask
    • 注意:一个timer指定的时间并不是准确时间,而是在到达这个时间后尽快执行回调,可能会因为系统正在执行别的事物而延迟
  • I/O callback阶段
    • 1.检查是否有处于pendingI/O回调,如果有,执行回调;如果没有,则直接退出该阶段
    • 2.检查process.nextTick任务,如果有,就全部执行
    • 3.检查microTask任务,如果有,全部执行
    • 4.退出该阶段
    • 注意:I/O阶段会执行除了closesetIntervalsetTimeoutsetImmediate的所有回调
    • 注意:上一轮循环中会有少数的I/O callback被延迟到这一轮循环中的这一阶段执行
  • idle,prepare:可省略,仅内部使用
  • poll阶段(轮询阶段)
    • 1.首先检查是否存在尚未完成的回调(类似于网络请求是否已经拿到数据),如果存在尚未完成的回调,则分两种情况执行:
      • 第一种情况:
        • 1.1如果有可用回调(到期的定时器和一些I/O事件等),则执行所有可用回调
        • 1.2检查process.nextTick任务,有就全部执行
        • 1.3检查microTask,有就全部执行
        • 1.4退出该阶段
      • 第二种情况
        • 1.1如果没有可用回调
        • 1.2检查是否有immediate回调,如果有,退出poll阶段(去check执行);如果没有,阻塞在此阶段,一直等到有新的事件通知为止
    • 如果不存在尚未完成的回调
      • 直接退出poll阶段
  • check阶段
    • 1.如果有setImmediate的回调,则立即全部执行
    • 2.检查是否有process.nextTick任务,如果有则全部执行
    • 3.检查是否有microTask任务,如果有则全部执行
    • 4.退出该阶段
  • close callbacks阶段
    • 1.执行close事件的callback
    • 2.检查process.nextTick任务,有则全部执行
    • 3.检查microTask任务,有则全部执行
    • 4.退出closing阶段
  • 最后:检查是否有活跃的handles(定时器、I/O等事件)
    • 如果有,继续进入下一轮循环
    • 如果没有,则结束事件循环,退出程序
  • Node循环中产生的执行队列:Timers Queue, I/O Queue, Check Queue, Close Queue

  • 循环过程:按照六个阶段进行循环,每次拿出当前阶段的队列中的所有任务然后全部执行,清空NextTick Queue,然后清空Microtask Queue,再执行下一阶段。全部六个阶段执行完毕之后,进入下轮循环,即:

    • 清空当前循环内的Timers Queue,清空NextTick Queue,清空Microtask queue
    • 清空当前循环的I/O Queue,清空NextTick Queue,清空Microtask queue
    • 清空当前循环的Check Queue,清空NextTick Queue,清空Microtask queue
    • 清空当前循环的Close Queue,清空NextTick Queue,清空Microtask queue
  • 注意:

    • 如果在timers阶段执行时创建了setImmediate,则会在check阶段执行;如果在timers阶段创建了setTimeout,由于timers已取出完毕,则会进入下轮循环

    • setTimeout优先级比setImmediate高

    • 每个阶段系统都会从当前阶段的callback queue中取出任务并执行,当队列为空或者被需要执行的callback数量达到上限时,就会进入下一个阶段

上述为本人在学习中的一些见解,如有错误烦请各位指正,感谢!
该文所有内容源自网络并结合了自己的理解,如有侵权请务必告知。