学习笔记:Node.js异步非阻塞IO与事件循环

78 阅读2分钟

参考:# 「Nodejs万字进阶」一文吃透异步I/O和事件循环

参考:# Node.js理论实践之《异步非阻塞IO与事件循环》

参考:# 面试官:说说你对Node.js 的理解?优缺点?应用场景?

事件循环机制

  1. timer阶段
  2. pending callback 阶段
  3. idle prepare 阶段
  4. poll 阶段
  5. check 阶段
  6. close 阶段
  • timers(定时器)阶段:执行setTimeoutsetInterval调度的回调。

  • pending callbacks(等待回调)阶段: 用于执行前一轮事件循环中被延迟到这一轮的I/O回调函数

  • idle,prepare(闲置,准备)阶段: 只能内部使用。

  • poll(轮询)阶段:最重要的阶段,执行I/O事件回调,在适当的条件下 node 会阻塞在这个阶段。

  • check(检查)阶段:执行 setImmediate 的回调。

  • close callbacks(关闭回调)阶段:执行close事件的回调, 如套接字(socket)或句柄(handle)突然关闭;

时间循环流程

image.png

  • 在每个事件的回调执行结束后,都会查看并清空microtask queue,在下文中用【@】表示
  • microtask queue:
    • nextTick microtask queue:process.nextTick调度的回调
    • others microtask queue:比如 promise.then
  1. 进入事件循环后,首先查看并清空timers queue中是否有待调用的setTimeoutsetInterval调度的回调,【@】
  2. 进入pending callbacks阶段,查看并清空poll queue中是否有前一轮时间循环中被延迟的待调用I/O回调,【@】
  3. 进入idle阶段,执行系统内部自己的任务,【@】
  4. 进入poll阶段,查看并清空poll queue中的I/O回调,【@】
  5. 进入check阶段,查看并清空check queue中是否有待调用的setImmediate调度的回调,【@】
  6. 进入close阶段,查看并清空close queue中是否有待调用的close调度的回调,【@】

非阻塞异步I/O

上文提到的poll(轮询)阶段执行的就是I/O回调。

image.png

主线程队列任务按顺序执行

  • 当遇到同步任务时,直接在主线程执行
  • 当遇到异步任务时,判断其是否为异步I/O任务
    • 如果是,则将其放入线程池中,交由I/O观察者,主线程不会被阻塞,会继续执行队列后续任务,当I/O任务完成时,会由I/O观察者将其加入队列
    • 如果不是,则将其加入队列,同样继续执行队列后续任务