主题
异步与事件循环
Node.js 以单个 JavaScript 主线程执行回调。I/O 完成、定时器到期等事件由事件循环调度;并不意味着所有工作都在单线程完成。
执行顺序
一次 JavaScript 调用栈清空后,Node.js 会先清空微任务,再进入下一轮事件循环:
process.nextTick()队列。- Promise 微任务队列(
queueMicrotask、Promise.then)。 - 事件循环阶段中的任务,例如定时器、I/O 回调、
setImmediate()。
process.nextTick() 优先级很高;递归排入会饿死 I/O,应仅用于兼容或确有必要的延后执行。普通异步编排优先使用 Promise 或 queueMicrotask()。
js
setTimeout(() => console.log('timeout'), 0)
setImmediate(() => console.log('immediate'))
Promise.resolve().then(() => console.log('promise'))
process.nextTick(() => console.log('nextTick'))
// 固定顺序:nextTick -> promise
// timeout 与 immediate 的相对顺序取决于调用位置与运行时状态。setTimeout 与 setImmediate
setTimeout(fn, 0):在定时器阈值到达后执行,不保证立刻执行。setImmediate(fn):在 I/O 轮询后、check 阶段执行。- 在 I/O 回调内部,
setImmediate通常先于setTimeout(0)。
阻塞风险
以下操作会占用主线程并延迟所有请求:同步 fs API、复杂正则、巨型 JSON 的同步解析、大循环和 CPU 密集加密/压缩。请求路径应保持短小;耗时任务改为分批、工作线程或队列任务。
