MST

星途 面试题库

面试题:Node.js 微任务与宏任务在复杂场景下的调度策略

在一个 Node.js 应用中,同时存在多个 I/O 操作、定时器任务以及 Promise 链式调用。如果要求在特定的业务逻辑下,优先执行某些宏任务中的特定部分,同时保证微任务不阻塞事件循环,你将如何设计调度策略?请结合 Node.js 的事件循环机制详细说明。
26.0万 热度难度
前端开发Node.js

知识考点

AI 面试

面试题答案

一键面试
  1. 理解 Node.js 事件循环机制
    • Node.js 的事件循环分为多个阶段:timers、I/O callbacks、idle, prepare、poll、check、close callbacks。
    • 宏任务(macrotask)如 setTimeout、setInterval、I/O 操作回调等在不同阶段执行,微任务(microtask)如 Promise.then、process.nextTick 等在当前宏任务执行结束后,事件循环进入下一阶段前执行。
  2. 优先执行宏任务特定部分的策略
    • 使用队列
      • 创建一个自定义队列来存储需要优先执行的宏任务特定部分。例如,对于 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();
    }
}
  1. 保证微任务不阻塞事件循环
    • 限制微任务执行数量
      • 可以设置一个计数器,在微任务执行过程中,若计数器达到一定阈值(如 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(() => {
        // 可延迟微任务逻辑
    });
});

通过上述调度策略,可以在特定业务逻辑下优先执行宏任务中的特定部分,同时保证微任务不阻塞事件循环。