在 Nodejs 事件循环的哪个阶段解析 Promise 的回调被执行?

ray*_*anJ 2 javascript event-loop node.js

根据这个答案

“重要的是要考虑到 Promise 中的 then/catch 回调是微任务,并将在 nextTick 任务之后执行”

Nodejs 文档提到 nextTickQueue 将在当前操作完成后处理,无论事件循环的当前阶段如何。这是否意味着已解决的承诺回调既不会在轮询阶段执行,也不会在挂起的回调阶段执行?

此外,该视频提到有一个queueMicroTask 队列,该队列在事件循环的当前阶段之后进行处理。所以我现在明白的是:

已解决的 Promise 回调将添加到queueMicroTask中,该回调将在nextTickQueue(回调传递给process.nextTick)之后进行处理,无论事件循环的当前阶段是什么,都会在nextTickQueue之后进行处理。

那是对的吗?如果不对请纠正我,我真的很困惑。

Dee*_*pal 11

微任务和 nextTicks 有一个重要的语义,这取决于 Node 版本。

在 Node v11 之前, nextTick 队列在事件循环的每个阶段之间执行(计时器、I/O、立即数、关闭处理程序是四个阶段)。因此,在 Node v11 之前,promise 回调也在事件循环的每个阶段之间执行。(我在这里详细介绍了这一点: https: //blog.insiderattack.net/promises-next-ticks-and-immediates-nodejs-event-loop-part-3-9226cbe7a6aa

然而,从 Node v11 开始,microtask每当 amicrotask作为程序执行的一部分添加到微任务队列时,事件循环就会跳转到队列。您可以使用以下代码片段进行实验。这同样适用于 nextTick 队列。您可以在这里阅读更多信息:https://blog.insiderattack.net/new-changes-to-timers-and-microtasks-from-node-v11-0-0-and-above-68d112743eb3

setImmediate(() => console.log('timeout1'));
setImmediate(() => {
    console.log('timeout2')
    Promise.resolve().then(() => console.log('promise'))
});
setImmediate(() => console.log('timeout3'));
setImmediate(() => console.log('timeout4'));
Run Code Online (Sandbox Code Playgroud)

上述代码的输出根据 Node.js 版本的不同而变化,如下所示:

$ node -v
v10.19.0
$ node test.js    
timeout1
timeout2
timeout3
timeout4
promise

$ nvm use 11
Now using node v11.15.0 (npm v6.7.0)
$ node test.js        
timeout1
timeout2
promise
timeout3
timeout4
Run Code Online (Sandbox Code Playgroud)

因此,重要的是要知道:nextTicksmicrotasks在 Node 版本 >=11 中具有更高的优先级,因为它们有机会在事件循环的当前阶段内进行处理。但在早期的 Node 版本中,nextTicksmicrotasks是在循环的每个阶段结束时执行的。

顺便说一句,重要的是要知道microtasks队列是引擎的一部分v8,而不是在 Node.js 运行时维护。但是,一旦 Node.js 完成队列,Node.js事件循环就会指示v8运行 all 。因此,promise 回调是在队列之后执行的。microtasksnextTicknextTick