Promise.all 与 [await x,await y] - 真的一样吗?

Ale*_*tos 1 javascript node.js es6-promise

这是一个基本问题,但我在任何地方都找不到答案。

我们有两种方法:

// consider someFunction1() and someFunction2() as functions that returns Promises

Approach #1:
return [await someFunction1(), await someFunction2()]

Approach #2:
return await Promise.all([someFunction1(), someFunction2()])
Run Code Online (Sandbox Code Playgroud)

我的团队领导说,这两种方法最终得到了相同的解决方案(两个功能并行执行)。但是,据我所知,第一种方法是await someFunction1()解析然后执行 someFunction2。

所以这就是问题,它真的是一样的吗,还是第二种方法有任何性能改进?非常欢迎提供证明!

Lui*_*ipe 8

不,你不应该接受:

return [await someFunction1(), await someFunction2()];
Run Code Online (Sandbox Code Playgroud)

是相同的:

return await Promise.all([someFunction1(), someFunction2()]);
Run Code Online (Sandbox Code Playgroud)

我还应该指出,await上面的内容return await是不需要的。查看这篇博文以了解更多信息。

他们是不同的


第一种方法(顺序)

让我们通过检查这两种替代方案的工作原理来确定差异。

[await someFunction1(), await someFunction2()];
Run Code Online (Sandbox Code Playgroud)

在这里,在async上下文中,我们创建一个数组文字。请注意,someFunction1被调用(每次调用时可能返回一个新承诺的函数)。

因此,当您调用 时someFunction1,会返回一个新的 Promise,然后它“锁定”上下文,async因为前面的await.

简而言之,await someFunction1()“阻止”数组初始化,直到返回的 Promise 得到解决(通过解决或拒绝)。

重复相同的过程至someFunction2

请注意,在第一种方法中,按顺序等待两个 Promise。因此,与使用的方法没有相似之处Promise.all。让我们看看为什么。

第二种方法(非顺序

Promise.all([someFunction1(), someFunction2()])
Run Code Online (Sandbox Code Playgroud)

当你申请时Promise.all,它需要一个可迭代的承诺。它会等待您给出的所有承诺进行解析,然后返回一组新的已解析值,但不要等到每个承诺解析后才等待另一个承诺。本质上,它同时等待所有的 Promise,因此它是一种“非顺序”。由于 JavaScript 是单线程的,你无法看出这是“并行”的,但从行为的角度来看却非常相似。

所以,当你传递这个数组时:

[someFunction1(), someFunction2()]
Run Code Online (Sandbox Code Playgroud)

您实际上传递了一组承诺(从函数返回)。就像是:

[Promise<...>, Promise<...>]
Run Code Online (Sandbox Code Playgroud)

请注意,承诺是在外部 Promise.all创建的。

因此,事实上,您正在将一系列承诺传递给Promise.all. 当它们都得到解析时,Promise.all返回解析值的数组。我不会详细解释如何Promise.all工作,为此,我建议您查看文档

您可以通过使用await. 就像这样:

const promise1 = someFunction1();
const promise2 = someFunction2();
return [await promise1, await promise2];
Run Code Online (Sandbox Code Playgroud)

promise1在等待时,promise2已在运行(因为它是在第一个 之前创建的await),因此行为类似于Promise.all's。

  • `return [awaitpromise1,awaitpromise2];` 与 `Approach2` 不同。它是“相似的”,但前提是承诺成功解决。如果失败,可能会导致未捕获的承诺拒绝。https://jsbin.com/pojumujoqe/1/edit?js,console,output 编辑:另请参阅[await Promise.all() 和多个等待之间有什么区别?](/sf/ask/3169959061/ ) (2认同)
  • @VLAZ,我说:“你可以复制这种“非顺序”方法[...]”,**不是**“你可以复制`Promise.all`行为[...]”。我很清楚这些差异,但我认为它们不属于问题的范围。不过,我可能会稍后编辑它以使这一点更清楚。尽管如此,还是谢谢你的提醒。:) 当然,另一个区别是 `[await p1,await p2]` 不会短路,与 `Promise.all([p1, p2])` 不同,但是,我不认为这是什么问题问。 (2认同)

VLA*_*LAZ 5

我的团队领导说,这两种方法最终得到了相同的解决方案(两个功能并行执行)。

这是不正确的。

但是,据我所知,第一种方法是await someFunction1()解析然后执行 someFunction2。

那是对的。

这是一个演示

方法一:

const delay = (ms, value) =>
  new Promise(resolve => setTimeout(resolve, ms, value));
  
async function Approach1() {
  return [await someFunction1(), await someFunction2()];
}
  
async function someFunction1() {
  const result = await delay(800, "hello");
  console.log(result);
  return result;
}

async function someFunction2() {
  const result = await delay(400, "world");
  console.log(result);
  return result;
}

async function main() {
  const start = new Date();
  const result = await Approach1();
  const totalTime = new Date() - start;
  console.log(`result: ${result}
    total time: ${totalTime}`);
}

main();
Run Code Online (Sandbox Code Playgroud)

结果是:

hello
world
result: hello,world
    total time: 1205
Run Code Online (Sandbox Code Playgroud)

这意味着someFunction1运行完成,然后再执行。是有顺序的someFunction2

方法2:

const delay = (ms, value) =>
  new Promise(resolve => setTimeout(resolve, ms, value));
  
async function Approach2() {
  return await Promise.all([someFunction1(), someFunction2()]);
}
  
async function someFunction1() {
  const result = await delay(800, "hello");
  console.log(result);
  return result;
}

async function someFunction2() {
  const result = await delay(400, "world");
  console.log(result);
  return result;
}

async function main() {
  const start = new Date();
  const result = await Approach2();
  const totalTime = new Date() - start;
  console.log(`result: ${result}
    total time: ${totalTime}`);
}

main();
Run Code Online (Sandbox Code Playgroud)

结果是:

world
hello
result: hello,world
    total time: 803
Run Code Online (Sandbox Code Playgroud)

这意味着在 之前someFunction2完成。两者是平行的。 someFunction1