根据返回类型 [duplicate] 的 promise 执行顺序

The execution order of the promise according to the return type [duplicate]

提问人:Won Jin Kim 提问时间:6/26/2023 最后编辑:trincotWon Jin Kim 更新时间:6/26/2023 访问量:55

问:

我想知道执行顺序因回调中返回的内容而异的原因:then

var a = Promise.resolve();

var b = a.then(function a_then() {
  console.log(1);
  var c = Promise.resolve();
  var d = c.then(function c_then() {
    console.log(2);
  });
  var e = d.then(function d_then() {
    console.log(3);
  });
  console.log(4);

  return c; // <--- this influences the output order

});

var f = b.then(function b_then() {
  console.log(5);
  var g = Promise.resolve();
  var h = g.then(function g_then() {
    console.log(6);
  });
  var i = h.then(function h_then() {
    console.log(7);
  });
  console.log(8);
});

console.log(9); 

如果没有那个(所以返回),输出顺序是:9,1,4,2,5,8,3,6,7,这个顺序被解释为我上一个问题的答案。return cundefined

但是添加它会将输出顺序更改为 9,1,4,2,3,5,8,6,7。return c

为什么现在输出值 3 在值 5 和 8 之前?为什么事件的顺序是这样的?

注意:返回 或 时,输出也会发生类似的变化。de

如果您能使用用作上一个问题答案的表格来解释它,那就太好了:

任务 行动 一个 b c d e f g h PromiseJob 队列
脚本 a = Promise.resolve() F - - - - - - - -
脚本 b = a.then(a_then) F ? - - - - - - - a_then
脚本 f = b.then(b_then) F ? - - - ? - - - a_then
脚本 console.log(9) F ? - - - ? - - - a_then
主机 出列a_then F ? - - - ? - - -
a_then console.log(1) F ? - - - ? - - -
a_then c = Promise.resolve() F ? F - - ? - - -
a_then d = c.then(c_then) F ? F ? - ? - - - c_then
a_then e = d.then(d_then) F ? F ? ? ? - - - c_then
a_then console.log(4) F ? F ? ? ? - - - c_then
a_then 返回解析b F F F ? ? ? - - - c_thenb_then
主机 出列c_then F F F ? ? ? - - - b_then
c_then console.log(2) F F F ? ? ? - - - b_then
c_then 返回解析d F F F F ? ? - - - b_thend_then
主机 出列b_then F F F F ? ? - - - d_then
b_then console.log(5) F F F F ? ? - - - d_then
b_then g = Promise.resolve() F F F F ? ? F - - d_then
b_then h = g.then(g_then) F F F F ? ? F ? - d_theng_then
b_then i = h.then(h_then) F F F F ? ? F ? ? d_then,g_then
b_then console.log(8) F F F F ? ? F ? ? d_then,g_then
b_then 返回解析f F F F F ? F F ? ? d_then,g_then
主机 出列d_then F F F F ? F F ? ? g_then
d_then console.log(3) F F F F ? F F ? ? g_then
d_then 返回解析e F F F F F F F ? ? g_then
主机 出列g_then F F F F F F F ? ?
g_then console.log(6) F F F F F F F ? ?
g_then 返回解析h F F F F F F F F ? h.then
主机 出列h_then F F F F F F F F ?
h_then console.log(7) F F F F F F F F ?
h_then 返回解析i F F F F F F F F F
主机 队列为空 F F F F F F F F F
JavaScript 异步 promise 返回 执行顺序

评论

1赞 trincot 6/26/2023
请把你的问题集中在一个(差异)上——现在它太宽泛了。仅以您返回的情况为例,并将您的问题集中在输出中特别让您感到惊讶的地方。c
1赞 jfriend00 6/26/2023
为什么你对返回不同的承诺会产生不同的结果感到困惑?当然可以。而且,当你有一大堆承诺实际上并不代表具有不确定时间的真实异步操作时,那么这在很大程度上就变成了一个无用的练习,因为它不是现实世界的承诺代码的工作方式。你可以很好奇,但不太可能学到很多对你在现实世界编码有帮助的东西。
1赞 jfriend00 6/26/2023
我同意 trincot 的评论。这是太多的问题。聚焦一个案例。解释你对那个案例的理解和不理解,并就那个案例问一个明确的问题。
1赞 trincot 6/26/2023
你能编辑你的问题并将其限制为其中之一吗?因此,同样,只关注一个案例,例如具有 .把它放在代码段中,这样你要询问的输出就是由代码段生成的,并解释输出的哪一部分是你意想不到的。return c
1赞 Community 6/26/2023
请澄清您的具体问题或提供其他详细信息,以准确说明您的需求。正如目前所写的那样,很难确切地说出你在问什么。

答:

1赞 trincot 6/26/2023 #1

当满足时,将执行回调。该回调的返回值决定了解析方式。如果该回调返回一个 promise(如),则 promise 的一个核心特征就会发挥作用:promise 不会简单地用返回的 promise 对象来履行,而是会保持待处理状态并“锁定”到返回的 promise 上:promise 的结算方式将决定 will settle 的方式 -- 的命运被锁定在 的 上。aa_thenbthencbcbbc

调用的 Promise 内部实现通过检查返回的值来实现此目的。它检测到这个返回的值是一个 thenable(它有一个方法),并且实际上会计划调用该方法(在本例中),因为这是了解该 thenable 的稳定状态的唯一方法(在本例中)。它会将自己的(内部)回调传递给该方法。a_thenthenthenc.thencthen

这是一个回调,它不是 JS 代码的一部分 -- 它由 Promise 实现提供(请参阅 Promise 解析函数步骤 13 上的 ECMAScript 规范)。此外,此调用将异步发生(请参阅同一规范中的步骤 14)。我们可以想象异步作业看起来像这样(简化):c.then

function lockin_b(c) {
    c.then(function fulfill_b(value) {
        _fulfill(value)
    });
}

...其中是可以解决的内部功能。_fulfillb

因此,总而言之,此锁定方案中涉及两个额外的异步作业:

  1. 由 Promise 内部的异步调用,以便锁定到c.thenbc
  2. 传递给 when 的回调的异步调用已解析。c.thenc

这意味着它将比省略的时间晚,因此输出 5 和 8 的回调也将稍后执行。breturn cb_then

下面是在执行该代码期间发生的一系列事件。

  • 第一列表示正在执行的内容(主脚本、从事件循环启动的函数或从 PromiseJob 队列中取消项目排队的主机)
  • 第二列包含正在计算的当前表达式/语句
  • 表示具有该名称的 promise 状态的列:待处理、已实现和已解决但尚未结算(即锁定)。ai?FR
  • 最后一列描绘了由主机管理的 PromiseJob 队列中存在的内容
任务 行动 一个 b c d e f g h PromiseJob 队列
脚本 a = Promise.resolve() F - - - - - - - -
脚本 b = a.then(a_then) F ? - - - - - - - a_then
脚本 f = b.then(b_then) F ? - - - ? - - - a_then
脚本 console.log(9) F ? - - - ? - - - a_then
主机 出列a_then F ? - - - ? - - -
a_then console.log(1) F ? - - - ? - - -
a_then c = Promise.resolve() F ? F - - ? - - -
a_then d = c.then(c_then) F ? F ? - ? - - - c_then
a_then e = d.then(d_then) F ? F ? ? ? - - - c_then
a_then console.log(4) F ? F ? ? ? - - - c_then
a_then return c解决b F R F ? ? ? - - - c_thenlockin_b
主机 出列c_then F R F ? ? ? - - - lockin_b
c_then console.log(2) F R F ? ? ? - - - lockin_b
c_then 返回解析d F R F F ? ? - - - lockin_bd_then
主机 出列lockin_b F R F F ? ? - - - d_then
lockin_b c.then(fulfill_b) F R F F ? ? - - - d_thenfulfill_b
lockin_b 返回 F R F F ? ? - - - d_then,fulfill_b
主机 出列d_then F R F F ? ? - - - fulfill_b
d_then console.log(3) F R F F ? ? - - - fulfill_b
d_then 返回解析e F R F F F ? - - - fulfill_b
主机 出列fulfull_b F R F F F ? - - -
fulfull_b _fulfill F F F F F ? - - - b_then
fulfull_b 返回 F F F F F ? - - - b_then
主机 出列b_then F F F F F ? - - -
b_then console.log(5) F F F F F ? - - -
b_then g = Promise.resolve() F F F F F ? F - -
b_then h = g.then(g_then) F F F F F ? F ? - g_then
b_then i = h.then(h_then) F F F F F ? F ? ? g_then
b_then console.log(8) F F F F F ? F ? ? g_then
b_then 返回解析f F F F F F F F ? ? g_then
主机 出列g_then F F F F F F F ? ?
g_then console.log(6) F F F F F F F ? ?
g_then 返回解析h F F F F F F F F ? h.then
主机 出列h_then F F F F F F F F ?
h_then console.log(7) F F F F F F F F ?
h_then 返回解析i F F F F F F F F F
主机 队列为空 F F F F F F F F F

当函数中的语句返回不同的承诺时,可以进行类似的分析。这是同样的原则。returnb_then