JavaScript 承诺 then() 排序
JavaScript Promise then() ordering
我还在学习 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
也会给出在我看来矛盾的结果。 1
在2
之前输出,但是6
在5
之前输出。
有人能给我解释一下吗?
我注意到,每次重新分配 p
都会得到我期望的顺序。
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);
});
你早早看到 6
的原因是你没有链接,而是分支。
当您调用 p.then().then().then()
时,您得到了 必须 以正确顺序执行的承诺链。
但是,如果您调用 p.then().then(); p.then()
,您会在 p
上附加 2 个承诺 - 本质上是创建一个分支,第二个分支将与第一个分支一起执行。
您可以通过确保将它们链接在一起来解决此问题 p = p.then().then(); p.then();
仅供参考,您几乎从不想分支,除非您将它们重新组合在一起(例如 Promise.all
),或者有意创建一个 "fire and forget" 分支。
为了清楚起见,让我们为示例中的每个承诺和功能命名:
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
已满,因此 f2
和 f6
被添加到队列中(按此顺序)。这是关键的一点,因为它意味着 f6
将在任何稍后排队的作业之前执行。
f2
被执行:打印“2”。
- (在
f2
内):new Promise
调用 f3
,它打印“3”并满足 p3
.
- (inside
f2
):由于p3
已经满足,所以将f4
加入队列,其结果将解析p4
.
f2
最终将p2
解析为p4
,也就是说一旦p4
满足,p2
. 也会满足
f6
被执行:打印“6”。 p6
圆满了。
f4
被执行:打印“4”。 p4
变得圆满了。 p2
已完成,因此 f5
被添加到队列中。
f5
被执行:打印“5”。 p5
圆满了。
我还在学习 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
也会给出在我看来矛盾的结果。 1
在2
之前输出,但是6
在5
之前输出。
有人能给我解释一下吗?
我注意到,每次重新分配 p
都会得到我期望的顺序。
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);
});
你早早看到 6
的原因是你没有链接,而是分支。
当您调用 p.then().then().then()
时,您得到了 必须 以正确顺序执行的承诺链。
但是,如果您调用 p.then().then(); p.then()
,您会在 p
上附加 2 个承诺 - 本质上是创建一个分支,第二个分支将与第一个分支一起执行。
您可以通过确保将它们链接在一起来解决此问题 p = p.then().then(); p.then();
仅供参考,您几乎从不想分支,除非您将它们重新组合在一起(例如 Promise.all
),或者有意创建一个 "fire and forget" 分支。
为了清楚起见,让我们为示例中的每个承诺和功能命名:
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
已满,因此f2
和f6
被添加到队列中(按此顺序)。这是关键的一点,因为它意味着f6
将在任何稍后排队的作业之前执行。f2
被执行:打印“2”。- (在
f2
内):new Promise
调用f3
,它打印“3”并满足p3
. - (inside
f2
):由于p3
已经满足,所以将f4
加入队列,其结果将解析p4
. f2
最终将p2
解析为p4
,也就是说一旦p4
满足,p2
. 也会满足
f6
被执行:打印“6”。p6
圆满了。f4
被执行:打印“4”。p4
变得圆满了。p2
已完成,因此f5
被添加到队列中。f5
被执行:打印“5”。p5
圆满了。