Node.js 事件循环


Node.js 事件循环

在 Node.js 中,所有的 I/O 操作都是异步的,即非阻塞的。这种操作模式使 Node.js 在进行高并发处理时非常高效。其底层的实现原理是事件循环。本文将详细解析Node.js 中的事件循环。

Node.js 中的事件循环可以分为以下几个阶段:

  1. timers 阶段:处理 setTimeout() 和 setInterval() 等定时器的回调函数。

  2. I/O callbacks 阶段:包含几乎所有的 I/O 回调事件,执行连接上的数据、请求和文件 I/O 等操作的回调。

  3. idle, prepare 阶段:只在内部使用。

  4. poll 阶段:在此阶段,Node.js 会阻止 I/O 操作,并执行对应的回调。它维护一个内部事件队列,如果在等待的时间内没有 I/O 事件,那么程序会阻塞在这个阶段。

  5. check 阶段:执行 setImmediate() 回调。

  6. close callbacks 阶段:关闭所有的 socket 服务器,执行关闭 socket 的回调。

事件循环的执行过程如下:

  1. 事件循环首先会从 timers 阶段开始,看是否有定时器的回调函数需要执行,如果有,就进入第 2 步。否则,进入第 3 步。

  2. 进入 I/O callbacks 阶段,看是否有可执行的异步 I/O 回调任务,如果有,就进入第 4 步。否则,进入第 3 步。

  3. 进入 poll 阶段,调用 Linux 内核的 epoll 或者 Unix 的 kqueue 机制,查看是否有待处理的请求,如果有,就执行回调函数。如果 poll 阶段为空闲的话,就会等待其他事件的回调函数被触发或执行 setImmediate() 注册的回调函数。如果有,就进入第 5 步。

  4. 进入 check 阶段,事件循环会执行 setImmediate() 注册的回调函数。

  5. 进入 close callbacks 阶段,执行关闭 socket 的回调。

在 Node.js 中,当事件循环的某一个阶段对应的回调函数执行完成之后,如果在 setImmediate() 中注册了回调函数,则会优先执行 setImmediate() 中注册的回调函数,而不是进入下一个阶段。

Node.js 的事件循环基于类似于 “Observer” 的设计模式,即使某个 event 在之前已经被触发,但如果有新的 event 注册的话,也会等待之前的 event 处理完毕之后再执行。

参考文献:

  1. Node.js官方文档 https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/

  2. 深入理解 Node.js 中的事件循环机制 https://www.ibm.com/developerworks/cn/opensource/os-cn-nodejs-eventloop/