Node.js 事件循环和浏览器事件循环有什么区别?
请比较 Node.js 和浏览器中事件循环机制的差异,特别是 process.nextTick 的作用。
回答
我还是少年
浏览器事件循环:
- 宏任务 → 清空微任务 → 渲染(requestAnimationFrame)→ 下一个宏任务
- 任务队列相对简单
Node.js 事件循环(libuv):基于 phases 的阶段模型
- timers:执行 setTimeout/setInterval 回调
- pending callbacks:执行延迟到下一轮的 I/O 回调
- idle, prepare:内部使用
- poll:获取新的 I/O 事件;若无定时器超时则阻塞等待
- check:setImmediate 回调
- close callbacks:关闭事件回调(如 socket 关闭)
process.nextTick 的特殊性:
- 不属于任何 phase,在当前 phase 结束后、下一 phase 前立即执行
- 优先级高于微任务队列
- 递归调用可能导致 I/O starvation,Node.js 有
maxListeners限制
执行顺序(Node.js):
process.nextTick(() => console.log('nextTick'));
Promise.resolve().then(() => console.log('promise'));
// Node 旧版:nextTick → promise
// Node 11+ 行为调整后:nextTick → promise(但 phases 边界处理更复杂)
主要差异表: | 特性 | 浏览器 | Node.js | |------|--------|--------| | 任务队列模型 | 宏任务+微任务 | phases 模型 | | process.nextTick | 无 | 有,优先于微任务 | | setImmediate | 无 | 有,check phase 执行 | | requestAnimationFrame | 有 | 无 | | UI 渲染 | 宏任务后 | 无 UI |