JavaScript Promise then() ordering

JavaScript Promise then() ordering

本文关键字:ordering then Promise JavaScript      更新时间:2023-09-26

我仍在学习JavaScript Promise s,遇到了一个我不理解的行为。

var o = $("#output");
var w = function(s) {
    o.append(s + "<br />");
}
var p = Promise.resolve().then(function() {
    w(0);
}).then(function() {
    w(1);
});
p.then(function() {
    w(2);
    return new Promise(function(r) {
        w(3);
        r();
    }).then(function() {
        w(4);
    });
}).then(function() {
    w(5);
});
p.then(function() {
    w(6);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output"></div>

我希望这些语句按顺序运行——也就是说,输出将是

0
1
2
3
4
5
6

相反,输出是

0
1
2
3
6
4
5

即使删除内部Promise,在我看来也会产生矛盾的结果。12之前输出,但65之前输出。

有人能向我解释一下吗?

我注意到,每次重新分配p都会给我们带来我所期望的顺序。

您早期看到6的原因是因为您没有连锁,而是分支。

当您调用p.then().then().then()时,您得到了一系列承诺,必须以正确的顺序执行这些承诺
然而,如果您调用p.then().then(); p.then(),那么p附带了两个promise——本质上是创建一个分支,第二个分支将与第一个分支一起执行。

您可以通过确保将它们链接到p = p.then().then(); p.then(); 来解决此问题

仅供参考,你几乎从不想分支,除非你把它们重新组合在一起(例如Promise.all),或者有意创建一个"着火后忘记"的分支。

r()做什么?

排序是不确定的,因为你当时在同一个承诺上->这具体指的是第二个和第三个链。

如果您正在执行以下操作,则订单可以得到保证:

var p = Promise.resolve().then(function() {
    w(0);
}).then(function() {
    w(1);
});
// Key difference, continuing the promise chain "correctly".
p = p.then(function() {
    w(2);
    return new Promise(function(r) {
        w(3);
        r();
    }).then(function() {
        w(4);
    });
}).then(function() {
  w(5);
});
p.then(function() {
  w(6);
});

为了清楚起见,让我们为示例中的每个承诺和函数命名:

var pz = Promise.resolve();
function f0() { w(0); }
var p0 = pz.then(f0);
function f1() { w(1); }
var p1 = p0.then(f1);  // p1 is 'p' in your example
function f2() {
    w(2);
    function f3(resolve_p3) {
        w(3);
        resolve_p3();
    }
    var p3 = new Promise(f3);
    function f4() { w(4); }
    var p4 = p3.then(f4);
    return p4;
}
var p2 = p1.then(f2);
function f5() { w(5); }
var p5 = p2.then(f5);
function f6() { w(6); }
var p6 = p1.then(f6);

让我们一步一步来看看会发生什么。首先是顶级执行:

  • pz被满足,因此pz.then(f0)立即将f0排队执行,其结果将解析p0
  • 一旦满足p0,则调度f1排队,并且其结果将解析p1
  • 一旦满足p1,则调度f2排队,并且其结果将解析p2
  • 一旦满足p2,则调度f5排队,并且其结果将解析p5
  • 一旦满足p1,则调度f6排队,并且其结果将解析p6

然后将运行排队的作业(最初仅为f0):

  • 执行f0:打印"0"。p0被满足,因此f1被添加到队列中
  • 执行f1:打印"1"。p1被满足,因此f2f6被添加到队列(按顺序)。这是关键的一位,因为这意味着f6将在稍后排队的任何作业之前执行
  • 执行f2:打印"2"
  • (在f2内部):new Promise调用f3,后者打印"3"并实现p3
  • (在f2内部):由于p3已经完成,所以将f4添加到队列中,其结果将解析p4
  • f2最终将p2解析为p4,这意味着一旦满足p4p2也将满足
  • 执行f6:打印"6"。CCD_ 54变为满足
  • 执行f4:打印"4"。CCD_ 56变为满足。p2被满足,因此f5被添加到队列中
  • 执行f5:打印"5"。CCD_ 60被满足