Node.js 事件循环
事件循环是 Node.js 实现异步非阻塞 I/O 的核心机制,决定了异步任务的执行顺序。
什么是事件循环
Node.js 是单线程的,通过事件循环处理并发操作。异步操作完成后,回调函数被放入队列,事件循环按顺序执行。
JavaScript
console.log('开始');
setTimeout(() => console.log('setTimeout'), 0);
Promise.resolve().then(() => console.log('Promise'));
console.log('结束');
// 输出顺序: 开始 -> 结束 -> Promise -> setTimeout
事件循环的六个阶段
| 阶段 | 说明 | 常见操作 |
|---|---|---|
| timers | 执行定时器回调 | setTimeout, setInterval |
| pending callbacks | 执行系统回调 | TCP 错误处理 |
| idle, prepare | 内部使用 | - |
| poll | 执行 I/O 回调 | 文件、网络操作 |
| check | 执行 setImmediate | setImmediate |
| close callbacks | 执行关闭回调 | socket.close |
微任务与宏任务
微任务(优先执行)
JavaScript
// Promise.then
Promise.resolve().then(() => console.log('微任务'));
// process.nextTick(最高优先级)
process.nextTick(() => console.log('nextTick'));
// 执行顺序: nextTick -> 微任务 -> 宏任务
宏任务
JavaScript
// setTimeout
setTimeout(() => console.log('宏任务1'), 0);
// setImmediate
setImmediate(() => console.log('宏任务2'));
// I/O 回调
fs.readFile('file.txt', () => console.log('I/O回调'));
执行顺序详解
JavaScript
console.log('1');
setTimeout(() => {
console.log('2');
Promise.resolve().then(() => console.log('3'));
}, 0);
Promise.resolve()
.then(() => console.log('4'))
.then(() => console.log('5'));
setTimeout(() => console.log('6'), 0);
console.log('7');
// 输出: 1 -> 7 -> 4 -> 5 -> 2 -> 3 -> 6
解释:
- 同步代码 1、7 先执行
- 微任务队列: 4 → 5
- timers 阶段: 2(触发微任务 3)
- 微任务队列: 3
- timers 阶段: 6
poll 阶段行为
JavaScript
// poll 阶段等待 I/O 事件
fs.readFile('file.txt', (err, data) => {
// 此回调在 poll 阶段执行
console.log('文件读取完成');
});
poll 阶段特点:
- 有 I/O 回调时,执行回调后进入下一阶段
- 无 I/O 回调时,等待新事件或进入下一阶段
- timers 有到期回调时,进入 timers 阶段
每个阶段结束后,会清空微任务队列再进入下一阶段。
要点总结
- 事件循环分六阶段:timers → pending → poll → check → close
- 微任务(Promise.nextTick)优先于宏任务执行
- process.nextTick 优先级最高,在当前操作后立即执行
- 同步代码最先执行,异步任务按事件循环顺序执行
📝 发现内容有误?点击此处直接编辑