全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-15 8 分钟 ✍️ juanwangdev

Node.js 微任务与宏任务

微任务优先于宏任务执行,理解两者的调度规则是掌握异步编程的关键。

任务分类

微任务(Microtask)

JavaScript
// 微任务类型
Promise.then/catch/finally
queueMicrotask()
process.nextTickNode.js 特有最高优先级

宏任务(Macrotask)

JavaScript
// 宏任务类型
setTimeout
setInterval
setImmediateNode.js 特有
I/O 回调

执行优先级

优先级从高到低:

  1. process.nextTick(nextTick 队列)
  2. Promise.then(微任务队列)
  3. setTimeout/setInterval(timers 阶段)
  4. setImmediate(check 阶段)
  5. I/O 回调(poll 阶段)

nextTick 与 Promise 对比

JavaScript
process.nextTick(() => console.log('nextTick'));
Promise.resolve().then(() => console.log('promise'));

console.log('sync');

// 输出: sync -> nextTick -> promise

Node.js 中 nextTick 队列独立于微任务队列,优先级更高:

JavaScript
// 执行顺序
process.nextTick(() => console.log('1'));
process.nextTick(() => console.log('2'));
Promise.resolve().then(() => console.log('3'));
Promise.resolve().then(() => console.log('4'));
process.nextTick(() => console.log('5'));

// 输出: 1, 2, 5, 3, 4
// 先清空 nextTick 队列,再清空微任务队列

queueMicrotask

JavaScript
// queueMicrotask 添加微任务
queueMicrotask(() => {
  console.log('微任务');
});

// 等同于 Promise.resolve().then()
Promise.resolve().then(() => {
  console.log('微任务');
});

微任务执行时机

每个阶段结束时,执行微任务:

JavaScript
setTimeout(() => {
  console.log('timer');
  Promise.resolve().then(() => console.log('微任务1'));
}, 0);

setTimeout(() => {
  console.log('timer2');
  Promise.resolve().then(() => console.log('微任务2'));
}, 0);

// 输出: timer -> 微任务1 -> timer2 -> 微任务2
// 每个 timer 后清空微任务队列

实例分析

JavaScript
console.log('A');

setTimeout(() => {
  console.log('B');
  Promise.resolve().then(() => console.log('C'));
}, 0);

Promise.resolve()
  .then(() => console.log('D'))
  .then(() => console.log('E'));

process.nextTick(() => {
  console.log('F');
  Promise.resolve().then(() => console.log('G'));
});

console.log('H');

// 执行顺序分析:
// 1. 同步: A, H
// 2. nextTick: F(触发微任务 G)
// 3. 微任务: D, E, G
// 4. timers: B(触发微任务 C)
// 5. 微任务: C

// 输出: A, H, F, D, E, G, B, C

微任务递归问题

JavaScript
// 微任务无限循环(阻塞事件循环)
function infiniteMicrotask() {
  Promise.resolve().then(infiniteMicrotask);
}
infiniteMicrotask();
// 事件循环被阻塞,定时器无法执行

// nextTick 无限循环
function infiniteNextTick() {
  process.nextTick(infiniteNextTick);
}
infiniteNextTick();
// 同样阻塞

避免在微任务中无限递归,会阻塞事件循环。

微任务与宏任务对比

特性微任务宏任务
执行时机当前阶段后下一阶段
优先级高于宏任务
队列每阶段后清空每阶段执行部分
代表Promise.thensetTimeout

setImmediate 与 setTimeout

JavaScript
// 非I/O回调中顺序不确定
setTimeout(() => console.log('timeout'), 0);
setImmediate(() => console.log('immediate'));

// I/O回调中 setImmediate 先执行
fs.readFile('file.txt', () => {
  setTimeout(() => console.log('timeout'), 0);
  setImmediate(() => console.log('immediate'));
});
// 输出: immediate -> timeout

原因:I/O 回调在 poll 阶段执行,下一阶段是 check(setImmediate)。

监控微任务执行

JavaScript
const { performance } = require('perf_hooks');

performance.on('resourceresolve', (item) => {
  console.log('Promise resolved');
});

// 检测微任务耗时
const timerify = performance.timerify;
const wrapped = timerify(asyncFunction);

要点总结

  • process.nextTick 优先级最高,独立队列
  • Promise.then 在 nextTick 之后执行
  • 每阶段结束后清空微任务队列
  • 微任务递归会阻塞事件循环
  • I/O 回调中 setImmediate 优先于 setTimeout

📝 发现内容有误?点击此处直接编辑

← 上一篇 Node.js 异步I/O与回调
下一篇 → Node.js try/catch/finally
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库