面试题答案
一键面试Node.js事件循环六个阶段
- timers:本阶段执行
setTimeout
和setInterval
回调。 - pending callbacks:执行系统操作的回调,比如 TCP 连接错误等。
- idle, prepare:仅系统内部使用。
- poll:检索新的 I/O 事件;执行与 I/O 相关的回调(除了
close
事件,timers
回调,setImmediate
回调)。如果没有setImmediate
等任务,会在此阶段阻塞等待新的 I/O 事件。 - check:执行
setImmediate
回调。 - close callbacks:执行
close
事件回调,例如socket.on('close', ...)
。
微任务和宏任务执行位置及顺序
- 宏任务:
- 在
timers
阶段执行setTimeout
、setInterval
的回调。 - 在
pending callbacks
阶段执行特定系统操作回调。 - 在
poll
阶段执行大部分 I/O 相关回调。 - 在
check
阶段执行setImmediate
回调。 - 在
close callbacks
阶段执行close
事件回调。
- 在
- 微任务:
- 每个宏任务执行完毕后,在进入下一个宏任务之前,会先执行微任务队列中的所有任务。微任务通常包括
process.nextTick
(Node.js 独有的,它的优先级高于其他微任务),Promise.then
,MutationObserver
(浏览器环境中有,Node.js 中没有直接关联)等。
- 每个宏任务执行完毕后,在进入下一个宏任务之前,会先执行微任务队列中的所有任务。微任务通常包括
执行顺序关系
- 事件循环从一个阶段到下一个阶段前,会先清空微任务队列。
- 微任务队列始终优先于宏任务队列执行。
举例说明
setTimeout(() => {
console.log('setTimeout callback');
}, 0);
Promise.resolve().then(() => {
console.log('Promise.then callback');
});
process.nextTick(() => {
console.log('process.nextTick callback');
});
// 输出顺序:
// process.nextTick callback
// Promise.then callback
// setTimeout callback
在这段代码中,process.nextTick
属于微任务且优先级高于 Promise.then
,所以先输出 process.nextTick callback
,然后 Promise.then
回调进入微任务队列也被执行,最后 setTimeout
属于宏任务,在当前宏任务(这里是主脚本执行完毕,可看作一个宏任务)结束,微任务队列清空后,在 timers
阶段被执行。