【问题标题】:Promise order invocation [duplicate]承诺订单调用[重复]
【发布时间】:2021-12-15 23:25:07
【问题描述】:

给定以下代码

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链合二为一,就可以保证最终结果的顺序。
  • @88jayto 输出为0 1 2 3 4 5 6
  • @StrahinjaAjvaz 更新了我的评论,这也可能有助于解释您所看到的:stackoverflow.com/questions/36870467/…
  • 仅供参考,理解为什么这在使用 Promise 编程中没有用处,原因有很多:1)如果你真的关心独立 Promise 链之间的顺序,那么你不需要制作链独立,因此您可以控制订单。 2) Promise 规范会不时更改,并且此详细程度可能会发生变化,3) 真实代码将具有具有不可预测完成的真实异步操作,因此此类问题不会在真实异步代码中发生。

标签: javascript es6-promise


【解决方案1】:

首先,这是两个独立的承诺链。在现实世界的异步编码中,这两个独立链中不同步骤之间的时间是完全断开的。 所以,这根本不是现实世界的问题。这是一项纯粹的学术活动或求知欲。

在现实世界的编码中,如果你关心这两个链中操作之间的相对顺序,你就不会有两个独立的 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 并等待它得到解决。尽管它已经在技术上得到解决,但从 Promise 中获得价值的唯一方法仍然是通过将 .then() 处理程序附加到它(或使用 await),这样仍然必须发生。这允许其他事情在它之前进入 Promise 作业队列。

因此,您可以立即看到4 的输出会延迟一些。这个延迟允许接下来输出2。然后,父promise 附加到Promise.resolve(4).then() 处理程序开始执行,所以现在第一个promise 链开始进入下一步。为此,它会将下一个.then() 处理程序作业添加到承诺作业队列中。但是,这不是队列中的下一个工作。队列中的下一个作业在输出2 后从第二个链放在那里。所以,我们接下来得到那个工作,输出 3 来了,最后的 4 开始了。

因此,通过 return Promise.resolve(4),我们不仅将这个链延迟了一个周期,而且我们还允许第二个承诺链中的下一个事件在第一个链中的下一个事件之前安排 - 因此基本上花费了我们作业队列中的两个位置。

因此,return Promise.resolve(4)return 4 之间的区别在于,由于将 .then() 处理程序添加到 Promise 作业队列的时间,后续的 .then() 处理程序在此处的相对顺序中下降了两个位置。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多