本文由一缘原创整理,系统梳理 Node.js 事件循环的原理、阶段、异步机制与实战技巧,适合所有 Node.js/后端开发者。

Node.js 事件循环与异步编程深度解析

事件循环是 Node.js 高并发、非阻塞 I/O 的核心。


1. 事件循环的六大阶段

  • timers(定时器):setTimeout/setInterval 回调
  • pending callbacks:部分系统操作的回调
  • idle, prepare:仅内部使用
  • poll:I/O 轮询、回调
  • check:setImmediate 回调
  • close callbacks:如 socket.on(‘close’)

2. 宏任务与微任务

  • 宏任务:setTimeout、setInterval、setImmediate、I/O
  • 微任务:process.nextTick、Promise.then/catch/finally
  • 每个阶段结束后会清空微任务队列

3. 事件循环执行顺序

setTimeout(() => console.log('timeout'), 0);
setImmediate(() => console.log('immediate'));
process.nextTick(() => console.log('nextTick'));
Promise.resolve().then(() => console.log('promise'));

输出(常见顺序):

nextTick
promise
timeout
immediate

4. process.nextTick 与 Promise 微任务区别

  • nextTick 优先级高于 Promise
Promise.resolve().then(() => console.log('promise'));
process.nextTick(() => console.log('nextTick'));

输出:

nextTick
promise

5. I/O、定时器与 setImmediate 的先后

const fs = require('fs');
fs.readFile(__filename, () => {
  setTimeout(() => console.log('timeout'), 0);
  setImmediate(() => console.log('immediate'));
});

输出(大多数情况下):

immediate
timeout

6. 异步 I/O 与高并发

  • Node.js 单线程事件循环,I/O 操作交给线程池或内核
  • 非阻塞 I/O 支持高并发
const fs = require('fs');
for (let i = 0; i < 3; i++) {
  fs.readFile(__filename, () => {
    console.log('read', i);
  });
}
console.log('main');

输出:

main
read 0
read 1
read 2

7. 实战:实现 sleep 函数

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
(async () => {
  console.log('start');
  await sleep(500);
  console.log('end');
})();

输出:

start
(0.5秒后) end

8. 事件循环调试与最佳实践

  • node --trace-eventsconsole.timeconsole.log 调试
  • 避免阻塞主线程(如大循环、同步 I/O)
  • 善用异步 API、Promise、async/await

结语

事件循环是 Node.js 的灵魂,理解它能让你写出高性能、可扩展的后端应用。欢迎留言交流更多 Node.js 深度问题!