确定这段代码输出的 JavaScript 规则是什么?:
Promise.resolve()
.then(() => console.log("Microtask 1"))
.then(() => console.log("Microtask 11"));
Promise.resolve()
.then(() => console.log("Microtask 2"))
.then(() => console.log("Microtask 22"))
这是输出:
Microtask 1
Microtask 2
Microtask 11
Microtask 22
但为什么这不是输出?:
Microtask 1
Microtask 11
Microtask 2
Microtask 22
最佳答案
你看到你看到的输出是因为 Microtask 11
的微任务没有排队直到 Microtask 1
的微任务运行,此时 的微任务微任务 2
已经在队列中等待。所以顺序是(跳过一些细节;更多内容见下文):
微任务 1
的队列微任务微任务 2
的队列微任务- 任务完成,开始处理微任务:
- 执行 #1 中排队的微任务
- 输出
微任务1
微任务 11
的队列微任务
- 输出
- 执行 #2 中排队的微任务
- 输出
微任务2
Microtask 21
的队列微任务
- 输出
- 执行 #3.1 中排队的微任务
- 输出
微任务 11
- 输出
- 执行 #3.2 中排队的微任务
- 输出
微任务 21
- 输出
- 执行 #1 中排队的微任务
因此,
Microtask 1 Microtask 2 Microtask 11 Microtask 21
But: Writing code that relies on the order of execution of disconnected promise chains / microtask sequences is asking for trouble. :-) You can only reason about it in relation to promises you know are already settled, and of course in the normal case, you don't know when (or even if) a promise will settle. Instead, if you need a specific order, connect the chains to ensure order.
Re skipped details: I sort of glossed over things in the main explanation to keep it short and clear, but for accuracy, let's look at:
Promise.resolve()
.then(() => console.log("Microtask 1"))
.then(() => console.log("Microtask 11"));
...就其本身而言,忽略第二个 promise 链以保持简单。
下面是该代码的执行方式(我的 blog post on promise 术语可能对阅读以下内容有所帮助):
- 执行
Promise.resolve()
,创建一个 在这种特殊情况下 由值undefined
实现的 promise 。 - 执行
.then(() => console.log("Microtask 1"))
,创建一个新函数并根据 Step 的 promise 调用then
1. 这将创建并返回一个新的 promise ,并且在这种特殊情况下,排队一个微任务来调用该函数,因为 promise 已经实现。 - 执行
.then(() => console.log("Microtask 11"))
,创建一个新函数并根据 Step 的 promise 调用then
2. 这将创建并返回一个新的 promise (我们在该代码中将其丢弃),并且由于步骤 2 中的 promise 仍处于待定状态,因此将函数作为履行处理程序添加到其中。 - 运行此代码的任务结束,因此 JavaScript 引擎处理微任务队列:
- 执行队列中的第一个微任务:
- 调用函数记录
Microtask 1
。 - 因为函数返回
undefined
,这不是一个 promise 或其他thenable ,引擎使用undefined 实现步骤 2 中的 promise 。
(如果函数返回了 promise 或其他 thenable,则该 promise 将解析为返回的 promise .)- 将微任务排队以调用在第 3 步中注册到该 promise 上的履行处理程序,该处理程序将在调用时记录
Microtask 11
。
- 将微任务排队以调用在第 3 步中注册到该 promise 上的履行处理程序,该处理程序将在调用时记录
- 调用函数记录
- 执行队列中的下一个微任务(记住我们忽略了这个描述中的另一个 promise 链,所以在这种情况下下一个微任务是记录
Microtask 11
的那个刚刚添加到队列中,而不是记录Microtask 2
) 的那个:- 调用函数记录
Microtask 11
。 - 由于该函数返回
undefined
,这不是 promise 或其他 thenable,因此引擎使用undefined 实现步骤 3 中的 promise 。
- 这不会执行任何操作,因为该 promise 上没有注册任何履行处理程序。
- 调用函数记录
- 执行队列中的第一个微任务:
关于javascript - 如何预测跨 Promise.then 链的微任务顺序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73797791/