面试题答案
一键面试- 理解 Node.js 事件循环机制
- Node.js 的事件循环分为多个阶段:timers、I/O callbacks、idle, prepare、poll、check、close callbacks。
- 宏任务(macrotask)如 setTimeout、setInterval、I/O 操作回调等在不同阶段执行,微任务(microtask)如 Promise.then、process.nextTick 等在当前宏任务执行结束后,事件循环进入下一阶段前执行。
- 优先执行宏任务特定部分的策略
- 使用队列:
- 创建一个自定义队列来存储需要优先执行的宏任务特定部分。例如,对于 I/O 操作的回调,若有特定部分需要优先执行,将其函数及相关参数放入队列。
- 对于定时器任务,在定时器回调中,判断是否属于优先执行部分,若是则放入队列。
- 控制执行顺序:
- 在适当的阶段(如 I/O callbacks 阶段结束后,进入 poll 阶段前)检查该队列。若队列不为空,则依次执行队列中的任务。
- 可以通过自定义函数封装队列任务执行逻辑,确保其执行时机符合要求。例如:
- 使用队列:
const priorityQueue = [];
// 将需要优先执行的任务放入队列
function addToPriorityQueue(task) {
priorityQueue.push(task);
}
// 在合适时机执行队列任务
function executePriorityQueue() {
while (priorityQueue.length > 0) {
const task = priorityQueue.shift();
task();
}
}
- 保证微任务不阻塞事件循环
- 限制微任务执行数量:
- 可以设置一个计数器,在微任务执行过程中,若计数器达到一定阈值(如 100),暂停微任务执行,让事件循环进入下一阶段。
- 例如,在 Promise.then 回调中添加计数器逻辑:
- 限制微任务执行数量:
let microtaskCounter = 0;
const microtaskThreshold = 100;
Promise.resolve().then(() => {
microtaskCounter++;
if (microtaskCounter >= microtaskThreshold) {
process.nextTick(() => {
// 继续执行剩余微任务逻辑
});
} else {
// 正常执行微任务逻辑
}
});
- 合理使用 process.nextTick:
- process.nextTick 会将任务放入微任务队列,但它的执行时机在当前函数执行结束后,Promise.then 微任务之前。
- 若有一些微任务逻辑可以拆分,对于一些相对不重要或可延迟执行的微任务部分,可使用 process.nextTick 延迟到下一轮微任务执行,避免一次性阻塞事件循环。例如:
Promise.resolve().then(() => {
// 重要微任务逻辑
process.nextTick(() => {
// 可延迟微任务逻辑
});
});
通过上述调度策略,可以在特定业务逻辑下优先执行宏任务中的特定部分,同时保证微任务不阻塞事件循环。