【问题标题】:What's the difference between Promise.all and adding promises using plus sign?Promise.all 和使用加号添加承诺有什么区别?
【发布时间】:2019-05-22 06:06:04
【问题描述】:

我正在尝试并行/同时运行几个异步函数。

我找到了两种解决方案,但不知道它们之间的区别。他们要么使用 Promise.all 要么使用添加符号。

如果一个函数抛出异常,我也看不出检查结果的意义。

await Promise.all([asyncFunction01(), asyncFunction02()])
const [p1, p2] = await Promise.all([asyncFunction01(), asyncFunction02()])
const p1 = asyncFunction01()
const p2 = asyncFunction02()
await p1 + await p2
const p1 = asyncFunction01()
const p2 = asyncFunction02()
const result = await p1 + await p2

在我看来,它们的运行方式都一样。它们都并行运行,并且在抛出错误的情况下快速失败。我喜欢第三个选项,因为它看起来更整洁。

那么有什么区别呢?我错过了什么吗?

【问题讨论】:

  • 标题具有误导性。你不添加承诺。等待一个承诺会产生已解决的承诺的价值,这不是一个承诺。
  • 仅就异步任务的“并行性”而言,这些块确实是等价的。然后是返回值的明显区别+最容易阅读/更具语义意义等,但这些都是意见。
  • @axiac 你是对的。我很高兴编辑它。有什么建议吗?

标签: javascript node.js ecmascript-6 es6-modules


【解决方案1】:

将两个等待的 Promise 添加在一起可能会或可能不会并行运行,具体取决于您何时初始化它们。如果在加法语句本身中初始化它们,它们将串联运行;第一个运行,然后当它完成时,第二个运行。见:

const p1 = () => new Promise((resolve, reject) => {
  setTimeout(() => { 
    console.log('p1')
    resolve(200)
  }, 5000)
})

const p2 = () => new Promise((resolve, reject) => {
  setTimeout(() => { 
    console.log('p2')
    resolve(100)
  }, 3000)
})

async function start() {
  const result = await p1() + await p2()
  console.log(result)
  Promise.all([p1(), p2()])
}

start()

如果将等待的 Promise 加在一起使它们连续运行,您会看到 p2p1 之前完成。事实并非如此。但是,当您使用 Promise.all 运行它们时,您会看到 p2 先完成。

正如@Kaiido 在 cmets 中指出的那样,OP 显示在等待它们相加之前开始承诺。在这种情况下,它们将并行运行:

const P1 = () => new Promise((resolve, reject) => {
  setTimeout(() => { 
    console.log('p1')
    resolve(200)
  }, 5000)
})

const P2 = () => new Promise((resolve, reject) => {
  setTimeout(() => { 
    console.log('p2')
    resolve(100)
  }, 3000)
})

async function start() {
  const p1 = P1()
  const p2 = P2()
  const result = await p1 + await p2
  console.log(result)
}

start()

您会看到 p2 在 p1 之前完成。所以你是对的,在功能上没有区别。因此,根据您的用例,它们的工作方式完全相同。不过有一些想法:

  1. 我认为 Promise.all 更清楚。你明确地向其他开发者(以及你未来的自己)表明你希望这些承诺并行运行。

  2. 使用 Promise.all,您不必为每个 Promise 创建变量。在很多情况下,Promise.all 会更干净。尽管在您将两个结果相加的示例中,使用 Promise.all 可能不会更干净:

const result = await Promise.all([p1(), p2()]
  .then(([r1, r2]) => r1 + r2)

【讨论】:

  • OP 的版本都没有这样做。所有这些都在“并行”运行。他们没有在做await asyncFunc1() + await asyncFunc2() 他们在做p1 = asyncFunc1(); p2= asyncFunc2(); await p1 + await p2 在代码遇到第一个await 的时候,两个 asyncFuncs 已经启动 => 他们并行运行。
  • 在您的示例中,第二个承诺是在第一个承诺解决后生成的。显然,第二个 Promise 不能与第一个 Promise 并行运行,因为它是在第一个 Promise 完成之后创建的。
  • “当您将两个等待的 Promise 添加在一起时,它们不会并行运行。” -- 是的,它们会并行运行。 Promise 代表eventual completion (or failure) of an asynchronous operation, and its resulting value。创建 Promise 时,异步操作已经开始,无论 Promise 是否为await-ed,它都会完成。
  • @axiac Kaiido 已经指出了这一点。我在几分钟前更新了我的答案。
【解决方案2】:

没有区别!只有两种替代方法来实现它。

return5 = async () => new Promise(
  resolve => setTimeout(resolve.bind(null, 5),250)
);

return8 = async () => new Promise(
  resolve => setTimeout(resolve.bind(null, 8),300)
);

g = async () => {
  console.time('await +');
  p1a = return5(); // async task started here
  p2a = return8(); // async task started here
  // waiting for them to all finish here and are printed
  console.log(await p1a + await p2a);
  console.timeEnd('await +');

  console.time('Promise all');
  // async tasks started immediately when the promises are passed
  // as well as waiting for their completion here
  const [p1, p2] = await Promise.all([return5(), return8()]);
  // results are here and printed sync
  console.log(p1 + p2);
  console.timeEnd('Promise all');
}
g();

【讨论】:

  • Promise.all() 解决方案等待 3 承诺解决。 Promise.all() 不会神奇地使其参数消失,它只是将它们包装起来。
  • 我怎样才能更好地表达它? Promise.all 同时运行 Promise,而 await 不会。欢迎编辑。
【解决方案3】:

Promisean object that represents the eventual completion (or failure) of an asynchronous operation, and its resulting value

Promise对象被创建时(当new Promise()返回时),异步操作已经开始,无论是await-ed,它都会运行完成,成功或失败。

await-ing Promise 只是完成这些事情的一种方式:

  • 将异步操作与启动它的代码同步;没有await,启动异步操作的代码通常在异步操作之前完成; await 暂停它直到异步操作完成并在之后恢复它,从而允许串行执行多个异步操作(当后面的操作依赖于必须在它之前运行的操作产生的结果时很有用);
  • 获取异步操作的结果,无论是成功时的值(或根本没有值)还是错误时的异常。

关于异步处理,await p1 + await p2await p1; await p2 的结果相同。 p1 承诺等待完成然后p2 承诺等待完成。如果p2p1 之前完成,await p2 会立即返回。

Promise.all() 的目的不是“并行运行 Promise”。承诺不会运行,它们只是数据(异步代码的结果)。 Promise 背后的异步代码运行并且它“并行”运行,因为这就是异步代码本质上所做的事情。它不需要Promise.all() 来做到这一点。

Promise.all() 的目的是产生一种机制,可以轻松地 await 处理所有封装的 Promise,并将所有封装的 Promises 的解析值捕获到单个值(数组)中。

当包装的 Promise 对象之一失败时,它也会失败。

对于完成/失败部分,await p1 + await p2 或多或少等同于 await Promise.all([p1, p2])

捕获并返回 p1p2 的解析值是另一回事。
只有当 p1p2 的解析值可以使用 + 组合时,await p1 + await p2 才有效操作员。它不适用于数组和对象。当结果必须以不同的方式组合时,即使是数字也不起作用。

【讨论】:

    猜你喜欢
    • 2017-11-15
    • 2017-07-10
    • 2012-12-24
    • 1970-01-01
    • 1970-01-01
    • 2016-10-16
    • 2017-07-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多