参考:# 「Nodejs万字进阶」一文吃透异步I/O和事件循环
参考:# Node.js理论实践之《异步非阻塞IO与事件循环》
参考:# 面试官:说说你对Node.js 的理解?优缺点?应用场景?
事件循环机制
- timer阶段
- pending callback 阶段
- idle prepare 阶段
- poll 阶段
- check 阶段
- close 阶段
-
timers(定时器)阶段:执行
setTimeout和setInterval调度的回调。 -
pending callbacks(等待回调)阶段: 用于执行前一轮事件循环中被延迟到这一轮的
I/O回调函数。 -
idle,prepare(闲置,准备)阶段: 只能内部使用。
-
poll(轮询)阶段:最重要的阶段,执行
I/O事件回调,在适当的条件下 node 会阻塞在这个阶段。 -
check(检查)阶段:执行
setImmediate的回调。 -
close callbacks(关闭回调)阶段:执行close事件的回调, 如套接字(socket)或句柄(handle)突然关闭;
时间循环流程
- 在每个事件的回调执行结束后,都会查看并清空
microtask queue,在下文中用【@】表示 - microtask queue:
- nextTick microtask queue:process.nextTick调度的回调
- others microtask queue:比如 promise.then
- 进入事件循环后,首先查看并清空
timers queue中是否有待调用的setTimeout和setInterval调度的回调,【@】 - 进入pending callbacks阶段,查看并清空
poll queue中是否有前一轮时间循环中被延迟的待调用I/O回调,【@】 - 进入idle阶段,执行系统内部自己的任务,【@】
- 进入poll阶段,查看并清空
poll queue中的I/O回调,【@】 - 进入check阶段,查看并清空
check queue中是否有待调用的setImmediate调度的回调,【@】 - 进入close阶段,查看并清空
close queue中是否有待调用的close调度的回调,【@】
非阻塞异步I/O
上文提到的poll(轮询)阶段执行的就是I/O回调。
主线程队列任务按顺序执行
- 当遇到同步任务时,直接在主线程执行
- 当遇到异步任务时,判断其是否为异步I/O任务
- 如果是,则将其放入线程池中,交由I/O观察者,主线程不会被阻塞,会继续执行队列后续任务,当I/O任务完成时,会由I/O观察者将其加入队列
- 如果不是,则将其加入队列,同样继续执行队列后续任务