JavaScript承诺then()排序

时间:2015-03-17 23:32:36

标签: javascript promise

我还在学习JavaScript Promise,我遇到了一个我不明白的行为。



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);
});
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output"></div>
&#13;
&#13;
&#13;

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

0
1
2
3
4
5
6

相反,输出是

0
1
2
3
6
4
5

即使移除内部Promise,也会产生与我相似的结果。在1之前输出2,但在6之前输出5

有人可以向我解释一下吗?

我注意到的是,每次重新分配p都会给我们预期的订单。

3 个答案:

答案 0 :(得分:28)

你早期看到6的原因是因为你没有链,你分支了。

当你致电p.then().then().then()时,你会得到一系列承诺必须以正确的顺序执行。
但是,如果你打电话给p.then().then(); p.then(),你就有2个承诺附加到p - 基本上是创建一个分支,第二个分支将与第一个分支一起执行。

您可以通过确保将它们链接在一起p = p.then().then(); p.then();

来解决此问题

仅供参考,除非你将它们重新组合在一起(例如Promise.all),否则你几乎不想分支,或者故意创建一个“火与忘记”分支。

答案 1 :(得分:4)

r()做什么?

订购是不确定的,因为您正在接受相同的承诺 - &gt;这特指第二和第三链。

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

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);
});

答案 2 :(得分:0)

为了清楚起见,让我们为示例中的每个承诺和功能起一个名字:

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
  • f1被安排为在p0完成后排队,其结果将解决p1
  • f2被安排为在p1完成后排队,其结果将解决p2
  • f5被安排为在p2完成后排队,其结果将解决p5
  • f6被安排为在p1完成后排队,其结果将解决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”。 p6得到满足。
  • f4被执行:打印“ 4”。 p4成为现实。 p2被满足,因此f5被添加到队列中。
  • f5被执行:打印“ 5”。 p5得到满足。