理解 setImmediate()
当您想异步执行某些代码,但希望尽快执行时,可以使用 Node.js 提供的 setImmediate()
函数:
setImmediate(() => {
// 执行某些操作
})
作为 setImmediate()
参数传递的任何函数都是一个回调函数,它将在事件循环的下一个迭代中执行。
setImmediate()
与 setTimeout(() => {}, 0)
(传递 0ms 超时时间)以及 process.nextTick()
和 Promise.then()
有什么区别?
传递给 process.nextTick()
的函数将在事件循环的当前迭代中执行,在当前操作结束之后。这意味着它将始终在 setTimeout
和 setImmediate
之前执行。
带有 0ms 延迟的 setTimeout()
回调函数与 setImmediate()
非常相似。执行顺序将取决于各种因素,但它们都将在事件循环的下一个迭代中运行。
process.nextTick
回调函数被添加到 process.nextTick 队列。Promise.then()
回调函数被添加到 promises microtask 队列。setTimeout
、setImmediate
回调函数被添加到 macrotask 队列。
事件循环首先执行 process.nextTick 队列 中的任务,然后执行 promises microtask 队列,然后执行 setTimeout
或 setImmediate
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。