Node事件循环

之前对 Node.js 总是有点似懂非懂的感觉,查阅一下官方文档https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/ 有一种恍然大悟的感觉

当 Node.js 启动时会初始化 event loop, 每一个 event loop 都会包含按如下顺序六个循环阶段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
   ┌───────────────────────────┐
┌─>│ timers │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ pending callbacks │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ idle, prepare │
│ └─────────────┬─────────────┘ ┌───────────────┐
│ ┌─────────────┴─────────────┐ │ incoming: │
│ │ poll │<─────┤ connections, │
│ └─────────────┬─────────────┘ │ data, etc. │
│ ┌─────────────┴─────────────┐ └───────────────┘
│ │ check
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
└──┤ close callbacks │
└───────────────────────────┘
  • timers 阶段: 这个阶段执行 setTimeout(callback) and setInterval(callback)预定的 callback;
  • I/O callbacks 阶段: 执行除了 close 事件的 callbacks、被 timers(定时器,setTimeout、setInterval 等)设定的 callbacks、setImmediate()设定的 callbacks 之外的 callbacks;
  • idle, prepare 阶段: 仅 node 内部使用;
  • poll 阶段: 获取新的 I/O 事件, 适当的条件下 node 将阻塞在这里;
  • check 阶段: 执行 setImmediate() 设定的 callbacks;
  • close callbacks 阶段: 比如 socket.on(‘close’, callback)的 callback 会在这个阶段执行.

每一个阶段都有一个装有 callbacks 的 fifo queue(队列),当 event loop 运行到一个指定阶段时,
node 将执行该阶段的 fifo queue(队列),当队列 callback 执行完或者执行 callbacks 数量超过该阶段的上限时,
event loop 会转入下一下阶段.

注意上面六个阶段都不包括 process.nextTick()

了解了这些就不难理解以下代码的执行顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
setTimeout(function() {
console.log('timeout1');
});

new Promise(function(resolve) {
console.log('promise1');
for (var i = 0; i < 1000; i++) {
i == 99 && resolve();
}
console.log('promise2');
}).then(function() {
console.log('then1');
});

console.log('global1');