为什么承诺状态在已解析为另一个承诺时显示待处理

问题描述 投票:0回答:1

下面的代码片段是我从著名的 YDKJS - 异步和性能系列中摘取的,为了便于理解,我做了一些更改。

var p3 = new Promise( function(resolve,reject){
    resolve( "B" );
} );
var p1 = new Promise( function(resolve,reject){
  resolve( p3 ); // equivalent to p3.then(res)
} );
var p2 = new Promise( function(resolve,reject){
    resolve( "A" );
} );
p1.then( function(v){
    console.log("In p1");
    console.log(p1);
} );
p2.then( function(v){
    console.log("In p2");
    console.log(p1);
} ); 

虽然记录结果的顺序是按照期望的,但 Promise p1 的状态显示待处理(在

console.log(p1)
),我无法理解。我尝试通过图片(最后)描述我到目前为止所理解的内容,以便您纠正我的错误之处。

结果

第 1 阶段

p1
解决已解决的承诺,
p3
。我知道
p1
仍将保持待定状态,并且尚未解析为值。但我听说
resolve(p3)
相当于

p3.then(res);  // res is a resolve callback of p1

因此,基于这个假设,由于

p3
已解析并且具有已注册的处理程序(
res
的回调
p1
),因此它将被插入到微任务队列(MTQ)中。

第 2 阶段

p2
均已解决并拥有已注册的处理程序(紫色),它将被附加到 MTQ。

第 3 阶段:现在由于堆栈上没有任何内容可以执行,首先插入 MTQ 中的 cb(黄色)将进入堆栈执行。 这是我的查询:当

res('B')
执行时,会将
p1
的状态标记为“已完成”吗?由于 res 是与
p1
相关的回调。

由于

p1
已经有一个已注册的处理程序(当
p1.then
被调用时),除了已完成之外,它不会附加到 MTQ,如第 4 阶段所示吗?

如果是这样,那么为什么即使在

第 5 阶段
p1 仍然显示为待处理?

第6阶段

p1
如何突然得到满足?

请帮我理解下面的图片描述哪里错了?

javascript es6-promise jobs asynccallback
1个回答
0
投票

当承诺状态已解析为另一个承诺时,为什么它显示pending

这只是术语。该实现不区分“未解决”和“已解决”待决状态。

res('B')
执行时,会将
p1
的状态标记为“已完成”吗?

是的。

p1
上注册的回调不会被附加到 MTQ,如第 4 阶段所示吗?为什么
p1
即使在第 5 阶段仍然显示为待处理?

你的推理大部分是正确的。是的,会的。事实上,如果您在

p3.then(resolve)
执行回调中写入
p1
,这正是会发生的情况,并且第 5 阶段
console.log
将打印 Promise {: 'B'}.

我听说

resolve(p3)
相当于
p3.then(resolve);
。所以基于这个假设......

这个假设并不完全有效。它在行为上确实大部分是等效的,但在微任务计时方面并不等效。当您将 thenable(承诺)传递给

resolve
时,它实际上会在新的微任务中安排对
.then(resolve, reject)
的调用,而不是从
resolve()
内同步调用它。

您可以阅读规范来了解如此复杂的细节,但实际上您不应该依赖它们(它们会不时发生变化 - 事实上,您错过的细节是建议更改)。你有两个独立的 Promise 链,你不应该对

p1
p2
之间的回调顺序做出任何假设。如果这很重要,你会让承诺相互依赖。

© www.soinside.com 2019 - 2024. All rights reserved.