理解 setImmediate()

当您想要异步执行某段代码,但又希望尽快执行时,一种选择是使用 Node.js 提供的 setImmediate() 函数

setImmediate(() => {
  // run something
});

作为 setImmediate() 参数传递的任何函数都是一个回调函数,它将在事件循环的下一次迭代中执行。

setImmediate()setTimeout(() => {}, 0)(传递 0 毫秒超时)、process.nextTick()Promise.then() 有何不同?

传递给 process.nextTick() 的函数将在当前操作结束后,在事件循环的当前迭代中执行。 这意味着它将始终在 setTimeoutsetImmediate 之前执行。

具有 0 毫秒延迟的 setTimeout() 回调函数与 setImmediate() 非常相似。 执行顺序将取决于多种因素,但它们都将在事件循环的下一次迭代中运行。

process.nextTick 回调函数被添加到 process.nextTick 队列Promise.then() 回调函数被添加到 promises microtask 队列setTimeoutsetImmediate 回调函数被添加到 macrotask 队列

事件循环首先执行 process.nextTick 队列中的任务,然后执行 promises microtask 队列,然后执行 macrotask 队列

这是一个例子,展示了 setImmediate()process.nextTick()Promise.then() 之间的顺序

const baz = () => console.log('baz');
const foo = () => console.log('foo');
const zoo = () => console.log('zoo');

const start = () => {
  console.log('start');
  setImmediate(baz);
  new Promise((resolve, reject) => {
    resolve('bar');
  }).then(resolve => {
    console.log(resolve);
    process.nextTick(zoo);
  });
  process.nextTick(foo);
};

start();

// start foo bar zoo baz

此代码将首先调用 start(),然后在 process.nextTick 队列中调用 foo()。 之后,它将处理 promises microtask 队列,该队列打印 bar 并同时在 process.nextTick 队列中添加 zoo()。 然后它会调用刚刚添加的 zoo()。 最后,调用 macrotask 队列中的 baz()

上述原则在 CommonJS 案例中成立,但请记住在 ES 模块中,例如 mjs 文件,执行顺序会有所不同

// start bar foo zoo baz

这是因为加载的 ES 模块被包装为异步操作,因此整个脚本实际上已经位于 promises microtask 队列中。 因此,当 Promise 立即被解析时,它的回调会被附加到 microtask 队列中。 Node.js 将尝试清除队列,直到移动到任何其他队列,因此您会看到它首先输出 bar

阅读时间
2 分钟
作者
flaviocopesMyles BorinsLaRuaNaahmadawaisclean99Claudio Wunder
贡献
编辑此页面