Skip to content

事件循环

Node 中的事件循环机制

plaintext
   ┌───────────────────────────┐
┌─>│           timers          │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
│  │     pending callbacks     │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
│  │       idle, prepare       │
│  └─────────────┬─────────────┘      ┌───────────────┐
│  ┌─────────────┴─────────────┐      │   incoming:   │
│  │           poll            │<─────┤  connections, │
│  └─────────────┬─────────────┘      │   data, etc.  │
│  ┌─────────────┴─────────────┐      └───────────────┘
│  │           check           │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
└──┤      close callbacks      │
   └───────────────────────────┘

1️⃣ timers 定时器

定时器阶段 setTimeout setInterval

  • 开始计时
  • 执行定时器的回调 (定时器的回调只能在这里执行)

2️⃣ pending callbacks

系统阶段 (不关心)

3️⃣ idle prepare

准备阶段 (不关心)

4️⃣ poll 轮询

轮询阶段,核心阶段

  • 如果回调队列里有待执行的回调函数 (非定时器回调,而是其它异步操作的回调)
    • 从回调队列中取出回调函数,同步执行 (按顺序执行),直到回调队列为空了,或者达到系统最大限度。
  • 如果回调队列为空
    • 如果有设置过 setImmediate
      • 进入下一个check阶段,目的:为了执行 setImmediate 所设置的回调
    • 如果未设置过 setImmediate
      • 在此阶段停留,等待回调函数被插入回调队列
      • 若定时器到点了,进入下一个 check 阶段,原因:为了走第五阶段,随后走第六阶段,随后第一阶段 (最终目的)

5️⃣ check

专门用于执行 setImmediate 所设置的回调阶段

6️⃣ close callbacks

关闭回调阶段

process.nextTick() 用于设置立即执行函数 (能在任意阶段优先执行)

javascript
// 延迟定时器
setTimeout(() => {
  console.log(1)
})

// 立即执行函数(回调)
setImmediate(() => {
  console.log(2);
});

// 立即执行函数(回调)
process.nextTick(() => {
  console.log(3);
});

console.log(4);

// 输出:4 3 1 2