Promise.all 和使用加号添加承诺有什么区别?

What's the difference between Promise.all and adding promises using plus sign?

我正在尝试 运行 parallel/concurrently 中的几个异步函数。

我找到了两个解决方案,但不知道它们之间的区别。他们使用 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

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

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

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

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();

将两个 awaited promise 添加到一起可能会也可能不会 运行 并行,具体取决于您何时初始化它们。如果您在加法语句本身中初始化它们,它们将 运行 串联;第一个 运行s,完成后,第二个 运行s。参见:

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()

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

正如@Kaiido 在评论中指出的那样,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.all 会更干净。尽管在您将两个结果相加的示例中,使用 Promise.all 可能不会更干净:

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

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

当创建Promise对象时(当new Promise()returns),异步操作已经开始,它将运行完成,成功或失败不管是否 await-ed 与否。

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

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

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

Promise.all()的目的不是"run the promises in parallel"。承诺不是 运行,它们只是数据(异步代码的结果)。 promises 运行s 和它 运行s "in parallel" 背后的异步代码,因为这是异步代码本质上所做的。它不需要 Promise.all() 来做到这一点。

Promise.all() 的目的是产生一种机制,可以轻松地 await 所有包装的承诺,并将所有包装的 Promise 的解析值捕获为单个值(一个数组)。

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

对于 completion/fail 部分,await p1 + await p2 或多或少等同于 await Promise.all([p1, p2])

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