何时使用 queueMicrotask() 与 process.nextTick()


queueMicrotask() API 是 process.nextTick() 的替代方案,它还使用用于执行 then、catch 和 finally 处理程序的相同微任务队列来延迟函数的执行。 在 Node.js 中,每次“下一个滴答队列”被排空时,微任务队列也会立即排空。

import { nextTick } from 'node:process';

Promise.resolve().then(() => console.log(2));
queueMicrotask(() => console.log(3));
nextTick(() => console.log(1));
// 输出:
// 1
// 2
// 3const { nextTick } = require('node:process');

Promise.resolve().then(() => console.log(2));
queueMicrotask(() => console.log(3));
nextTick(() => console.log(1));
// 输出:
// 1
// 2
// 3

对于_大多数_用户空间用例,queueMicrotask() API 提供了一种可移植且可靠的延迟执行机制,该机制适用于多个 JavaScript 平台环境,应该比 process.nextTick() 更受青睐。 在简单的场景中,queueMicrotask() 可以直接替代 process.nextTick()

console.log('start');
queueMicrotask(() => {
  console.log('microtask callback');
});
console.log('scheduled');
// 输出:
// start
// scheduled
// microtask callback

两个 API 之间一个值得注意的区别是 process.nextTick() 允许指定额外值,这些值将在调用时作为参数传递给延迟函数。 使用 queueMicrotask() 实现相同的结果需要使用闭包或绑定函数:

function deferred(a, b) {
  console.log('microtask', a + b);
}

console.log('start');
queueMicrotask(deferred.bind(undefined, 1, 2));
console.log('scheduled');
// 输出:
// start
// scheduled
// microtask 3

从下一个滴答队列和微任务队列中引发的错误的处理方式存在细微差别。 在排队的微任务回调中抛出的错误应该在可能的情况下在排队的回调中处理。 如果不是,则可以使用 process.on('uncaughtException') 事件句柄来捕获和处理错误。

如有疑问,除非需要 process.nextTick() 的特定功能,否则请使用 queueMicrotask()

The queueMicrotask() API is an alternative to process.nextTick() that also defers execution of a function using the same microtask queue used to execute the then, catch, and finally handlers of resolved promises. Within Node.js, every time the "next tick queue" is drained, the microtask queue is drained immediately after.

import { nextTick } from 'node:process';

Promise.resolve().then(() => console.log(2));
queueMicrotask(() => console.log(3));
nextTick(() => console.log(1));
// Output:
// 1
// 2
// 3const { nextTick } = require('node:process');

Promise.resolve().then(() => console.log(2));
queueMicrotask(() => console.log(3));
nextTick(() => console.log(1));
// Output:
// 1
// 2
// 3

For most userland use cases, the queueMicrotask() API provides a portable and reliable mechanism for deferring execution that works across multiple JavaScript platform environments and should be favored over process.nextTick(). In simple scenarios, queueMicrotask() can be a drop-in replacement for process.nextTick().

console.log('start');
queueMicrotask(() => {
  console.log('microtask callback');
});
console.log('scheduled');
// Output:
// start
// scheduled
// microtask callback

One note-worthy difference between the two APIs is that process.nextTick() allows specifying additional values that will be passed as arguments to the deferred function when it is called. Achieving the same result with queueMicrotask() requires using either a closure or a bound function:

function deferred(a, b) {
  console.log('microtask', a + b);
}

console.log('start');
queueMicrotask(deferred.bind(undefined, 1, 2));
console.log('scheduled');
// Output:
// start
// scheduled
// microtask 3

There are minor differences in the way errors raised from within the next tick queue and microtask queue are handled. Errors thrown within a queued microtask callback should be handled within the queued callback when possible. If they are not, the process.on('uncaughtException') event handler can be used to capture and handle the errors.

When in doubt, unless the specific capabilities of process.nextTick() are needed, use queueMicrotask().