下面的代码片段是我从著名的 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
如何突然得到满足?
请帮我理解下面的图片描述哪里错了?
当承诺状态已解析为另一个承诺时,为什么它显示pending?
这只是术语。该实现不区分“未解决”和“已解决”待决状态。
当
执行时,会将res('B')
的状态标记为“已完成”吗?p1
是的。
在
上注册的回调不会被附加到 MTQ,如第 4 阶段所示吗?为什么p1
即使在第 5 阶段仍然显示为待处理?p1
你的推理大部分是正确的。是的,会的。事实上,如果您在
p3.then(resolve)
执行回调中写入 p1
,这正是会发生的情况,并且第 5 阶段 console.log
将打印 Promise {我听说
相当于resolve(p3)
。所以基于这个假设......p3.then(resolve);
这个假设并不完全有效。它在行为上确实大部分是等效的,但在微任务计时方面并不等效。当您将 thenable(承诺)传递给
resolve
时,它实际上会在新的微任务中安排对 .then(resolve, reject)
的调用,而不是从 resolve()
内同步调用它。
您可以阅读规范来了解如此复杂的细节,但实际上您不应该依赖它们(它们会不时发生变化 - 事实上,您错过的细节是建议更改)。你有两个独立的 Promise 链,你不应该对
p1
和 p2
之间的回调顺序做出任何假设。如果这很重要,你会让承诺相互依赖。