【问题标题】:What is the difference between returned Promise?返回的 Promise 有什么区别?
【发布时间】:2020-02-01 16:23:03
【问题描述】:

有两种情况,都返回 Promise 并与以下 then 方法链接。 但结果顺序不同。 一些注意事项: Promise.resolve(value) -> 返回立即履行的带有值的 Promise。 在 then 方法中,当我们再次返回值时,它会返回已完成的 Promise 和该值。 逻辑上应该没有区别。两者都是即时... 提前谢谢...

Promise.resolve(1)
  .then((v) => {
    console.log(v);
    return Promise.resolve(v + 1);
  })
  .then((v) => {
    console.log(v);
    return Promise.resolve(v + 1);
  })
  .then((v) => {
    console.log(v);
    return v + 1;
  })
  .then((v) => {
    console.log(v);
    return v + 1;
  });

Promise.resolve(10)
  .then((v) => {
    console.log(v);
    return v + 1;
  })
  .then((v) => {
    console.log(v);
    return v + 1;
  })
  .then((v) => {
    console.log(v);
    return v + 1;
  })
  .then((v) => {
    console.log(v);
    return v + 1;
  });

//Result on the console:
//1
//10
//11
//12
//2
//13
//3
//4

//

Promise.resolve(1)
  .then((v) => {
    console.log(v);
    return v + 1;
  })
  .then((v) => {
    console.log(v);
    return v + 1;
  })
  .then((v) => {
    console.log(v);
    return v + 1;
  })
  .then((v) => {
    console.log(v);
    return v + 1;
  });

Promise.resolve(10)
  .then((v) => {
    console.log(v);
    return v + 1;
  })
  .then((v) => {
    console.log(v);
    return v + 1;
  })
  .then((v) => {
    console.log(v);
    return v + 1;
  })
  .then((v) => {
    console.log(v);
    return v + 1;
  });

//Result on the console:
//1
//10
//2
//11
//3
//12
//4
//13

【问题讨论】:

  • 其他异步任务的执行在实际应用中或多或少是未定义的。 (你可以进入微任务和事件循环的细节,但你为什么要这样做呢?)只要每个promise都返回预期的结果,你就不应该太在意when i> 它到了。
  • @deceze 谢谢。我只是想不明白它背后的逻辑)

标签: javascript promise


【解决方案1】:

有一个重要的区别:记住then 返回一个promise(我们称之为promise T)。当你这样做时

return Promise.resolve(v + 1);

...您正在将 promise T 解析为 promise(我们称其为 promise B)。但是当你这样做时:

return v + 1;

...您正在将 promise T 解析为立即值。

将promise T 解析为promise B 在解析周期中引入了一个额外的“tick”。与其让 Promise T 排队调用它的解析处理程序,它必须等到 Promise B 调用解析处理程序 T 必须设置它,然后 然后 调用它的解析处理程序。因此额外的“tick”(基本上是微任务队列的另一个循环)。

更简单的例子,注意它在“First 2”之前记录了“Second 2”:

Promise.resolve(1)
    .then(v => Promise.resolve(v + 1))
    .then(v => console.log(`First: ${v}`));
Promise.resolve(1)
    .then(v => v + 1)
    .then(v => console.log(`Second: ${v}`));

...而如果您没有额外的承诺,它会在“第二个 2”之前记录“前 2”:

Promise.resolve(1)
    .then(v => v + 1)
    .then(v => console.log(`First: ${v}`));
Promise.resolve(1)
    .then(v => v + 1)
    .then(v => console.log(`Second: ${v}`));

这个额外的勾号最近被移除了用于执行类似return await somePromise(而不仅仅是return somePromise)的async 函数,因为它可以可靠地移除用于通过async/await 在内部处理的本机承诺。但我不确定是否可以为您的情况可靠地删除它,和/或这样做是否会引起那些必须这样做的人的任何重大关注。这需要将 then 处理程序返回的 native 承诺与任何其他 thenable¹ 不同,这可能是有问题的。 (但我不确定会是这样。)


¹ thenable 与 promise:https://promisesaplus.com

【讨论】:

  • 虽然这在技术上是正确的,但我认为没有任何相关方意味着这种情况,这是一个巧合。人们大多不希望 zalgo 和代码基于同步/异步具有不同的执行顺序。 Promise.resolve 以这种方式工作的事实只是因为我们不想要第二个函数(Promise.cast esdiscuss.org/topic/promise-cast-and-promise-resolve),它最终同时执行了 map 和 flatMap。
  • @BenjaminGruenbaum - 我不是在说意图,也不能。 :-) (虽然“巧合”似乎是一种错误的描述;每个重要参与的人都会从具有规范定义的语义的处理程序中意识到return v + 1 和return Promise.resolve(v + 1) 之间的区别。)我只是在说什么解释OP 看到的行为。
  • 那只是因为它可能更容易指定。我记得在某个合作峰会(2018 年柏林?)上与 Benedikt、Maya 和 Daniel 进行了一次讨论,当时 Benedikt 向我展示了 4 个 promises 的东西,我就像“嗯,这不是故意的——我们应该改变它而不是优化它规格”。我认为这可能是其中一种情况,它只是碰巧等待了一个不需要的额外微滴。
  • 另外 - 我不反对 - 我只是觉得好笑 :D 这从来都不是一个差异,return foo 应该隐含地是 return Promise.resolve(foo) 并且时间差异(和严格的微任务调度)是一个ECMAScript 规范的工件 - Promises/A+ 规范没有这样的要求。它只需要执行上下文堆栈只包含平台代码。
  • @sharpenedguy Promise.resolve(Promise.resolve(1)) 与上面的情况略有不同,并且没有添加额外的层,因为它有一个优化:当您将承诺传递给 Promise.resolve 时,@ 987654323@ 抽象操作检查该 Promise 的构造函数是否与您调用 resolve 的 Promise 相同。如果是这样,它只返回您传入的承诺,使外部调用完全不操作。这意味着const p = Promise.resolve(1); console.log(p === Promise.resolve(p)); 记录true。
【解决方案2】:

请记住,javascript 是单线程的,并且会将所有方法添加到队列中。我在下面所做的是在某种程度上应该如何编写承诺。

Javascript 在第一列中添加所有任务,通过队列执行所有命令,然后在第 2 列和第 3 列中添加更多任务,因为它们是在异步方法中找到的。

这样看还是挺合乎逻辑的。

【讨论】:

  • "Javascript 将所有任务添加到第一列" - 不,它没有。 then 将处理程序附加到承诺 - 同步 - 但处理程序仅在承诺解决时才安排在队列中。
猜你喜欢
  • 2017-02-06
  • 2011-11-30
  • 2016-09-18
  • 2019-01-20
  • 2011-12-24
  • 2011-09-29
  • 2019-10-08
  • 2012-03-22
  • 2016-06-28
相关资源
最近更新 更多