给出以下代码
Promise.resolve().then(() => {
console.log(0);
return Promise.resolve(4);
}).then((res) => {
console.log(res)
})
Promise.resolve().then(() => {
console.log(1);
}).then(() => {
console.log(2);
}).then(() => {
console.log(3);
}).then(() => {
console.log(5);
}).then(() => {
console.log(6);
})
我以为这会给出
0 4 1 2 3 5 6
,但输出是0 1 2 3 4 5 6
。
任何人都可以评论为什么会出现这种情况吗?
首先,这是两个独立的 Promise 链。 在现实世界的异步编码中,这两个独立链中不同步骤之间的时序是完全断开的。 所以,这根本不是一个现实世界的问题。 这是一种纯粹的学术练习或一种求知欲。
在现实世界的编码中,如果您关心这两个链中操作之间的相对顺序,则不会有两个独立的 Promise 链。 相反,您可以将它们链接到一条链中,您可以在其中控制顺序。
哦,甚至偶尔会对 Javascript/promise 规范进行更改,这也可能会影响这种详细程度。 几年前,为了提高 Promise 性能,规范对
await
的工作方式进行了更改,这确实影响了此类测试场景中的详细时序(使用 await
时)。
也就是说,唯一真正的问题是为什么
4
的输出会出现在它的位置。 我们首先可以通过更改代码来检查问题,让第一个 .then()
处理程序不返回 Promise.resolve(4)
,而是只执行 return 4;
。 当我们这样做时,这就是您得到的:
Promise.resolve().then(() => {
console.log(0);
return 4;
}).then((res) => {
console.log(res)
})
Promise.resolve().then(() => {
console.log(1);
}).then(() => {
console.log(2);
}).then(() => {
console.log(3);
}).then(() => {
console.log(5);
}).then(() => {
console.log(6);
})
并且,你得到输出:
0
1
4
2
3
5
6
好的,那么现在问题就简化为为什么
return Promise.resolve(4)
会导致4
相对于return 4;
延迟两个位置?
这与从
.then()
处理程序返回承诺与返回普通值的区别有关。 当您返回一个值时,链中的下一个 Promise 可以立即使用该值进行解析,并且附加到该 Promise 的后续 .then()
处理程序可以立即添加到 Promise 作业队列中。
但是,当您返回一个 Promise 时,链中的下一个 Promise 必须通过向其添加
.then()
处理程序并等待它得到解决来监视返回的 Promise。 尽管它已经在技术上得到解决,但从承诺中获取价值的唯一方法仍然是通过附加一个 .then()
处理程序(或使用 await
),所以仍然必须发生。 这允许其他事情先于它进入承诺作业队列。
因此,您可以立即看到
4
输出会延迟一些。 此延迟允许接下来输出 2
。 然后,由父 Promise 附加到 .then()
的 Promise.resolve(4)
处理程序开始执行,所以现在第一个 Promise 链开始进入下一步。 为此,它会将下一个 .then()
处理程序作业添加到承诺作业队列中。 但是,这不是队列中的下一个工作。 队列中的下一个作业在输出2
后从第二条链放入那里。 因此,我们接下来完成这项工作,输出 3
出现,最后的 4
之后开始。
因此,通过 return
Promise.resolve(4)
,我们不仅将该链延迟了一个周期,而且还允许第二个 Promise 链中的下一个事件在第一个链中的下一个事件之前安排 - 因此实际上使我们损失了两个位置在作业队列中。
因此,
return Promise.resolve(4)
和 return 4
之间的区别在于,由于将 .then()
处理程序添加到承诺作业队列的时间,后续 .then()
处理程序在此相对顺序中下降了两个位置。