NodeJS Promise.all vs [waiting x,waiting y] -真的一样吗?[duplicate]

voj3qocg  于 2023-01-25  发布在  Node.js
关注(0)|答案(5)|浏览(120)
    • 此问题在此处已有答案**:

Any difference between await Promise.all() and multiple await?(6个答案)
1年前关闭。
这是一个基本的问题,但是我在任何地方都找不到答案。
我们有两种方法:

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

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

Approach #2:
return await Promise.all([someFunction1(), someFunction2()])

我的团队领导说这两种方法最终得到了相同的解决方案(两个函数并行执行),但是,据我所知,第一种方法将await someFunction1()解析,然后执行someFunction2。
所以这就是问题所在,第二种方法是否真的相同,或者是否有任何性能改进?非常欢迎提供证明!

5ktev3wc

5ktev3wc1#

不,您不应接受:

return [await someFunction1(), await someFunction2()];

等同于:

return await Promise.all([someFunction1(), someFunction2()]);

我还应该注意到,上面的return await中的await是不需要的。查看this blog post了解更多信息。
他们是不同!

第一种方法(顺序)

让我们通过检查这两个选项中的每一个如何工作来确定差异。

[await someFunction1(), await someFunction2()];

这里,在async上下文中,我们创建了一个数组常量。注意,someFunction1被调用了(一个函数,每次被调用时可能返回一个新的promise)。
因此,当您调用someFunction1时,将返回一个新的promise,然后它将"锁定" async上下文,因为前面的await
简而言之,await someFunction1() "阻塞"数组初始化,直到返回的承诺得到解决(通过得到解决或拒绝)。
someFunction2重复相同的过程。
请注意,在第一种方法中,两个承诺是按顺序等待的,因此与使用Promise.all的方法没有相似之处,让我们看看为什么。

第二种方法(* 非连续 *)

Promise.all([someFunction1(), someFunction2()])

当你应用Promise.all时,它期待一个可迭代的承诺。它等待你给出的所有承诺都被解析,然后返回一个新的解析值数组,但是不要等到每个承诺都被解析了才等待另一个。本质上,它同时等待所有的承诺,所以它是一种"非顺序"。由于JavaScript是单线程的,你不能判断这种"并行",但是从行为的Angular 来看非常相似。
因此,当传递此数组时:

[someFunction1(), someFunction2()]

你实际上传递了一个promise数组(从函数返回),类似于:

[Promise<...>, Promise<...>]

注意,承诺是在**Promise.all之外创建的。
所以你实际上是在传递一个promise数组给Promise.all,当它们都被解析后,Promise.all返回解析值的数组,我不会详细解释Promise.all是如何工作的,为此,我建议你去看看documentation
你可以复制这种"非连续"的方法,用await
之前**创建承诺。

const promise1 = someFunction1();
const promise2 = someFunction2();
return [await promise1, await promise2];

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

6jjcrrmo

6jjcrrmo2#

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

方法1:

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

结果为:

hello
world
result: hello,world
    total time: 1205

这意味着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();

结果为:

world
hello
result: hello,world
    total time: 803

这意味着someFunction2someFunction1之前 * 完成,两者是并行的。

kcwpcxri

kcwpcxri3#

很容易看出区别

function createTimer(ms, id) {
      console.log(`id: ${id} started ${new Date()}`);
      return new Promise((res, rej) => {
        setTimeout( () => {
          console.log(`id: ${id} finished ${new Date()}`);
          res(id);      
        }, ms );
      });
    }

    (async function() {

      var result1 = [await createTimer(5000, '1'), await createTimer(5000, '2')];
      var result2 = await Promise.all([createTimer(5000, '3'), createTimer(5000, '4')]);

      console.log(result1);
      console.log(result2);

    })();

第一个命令启动1,当1完成时,它启动2;第二个命令几乎同时启动34

dxxyhpgq

dxxyhpgq4#

如果你从一个函数开始,它模拟做一些工作,在工作的各个阶段有输出,但要花一些时间

function someFunction1(){
   return new Promise(resolve => {
       let i = 0;
       const intervalId = setInterval(() => {
          i++;
          console.log("someFunction1", i);
          if(i == 5){
            clearInterval(intervalId)
            resolve(1); 
          }
       }, 1000);
   });
}

然后你用第二个类似的方法复制它,你插入你的两个方法,你会看到使用Promise.all的方法是并行的,而使用2个await调用的方法是串行的。
平行

function someFunction1(){
   return new Promise(resolve => {
       let i = 0;
       const intervalId = setInterval(() => {
          i++;
          console.log("someFunction1", i);
          if(i == 5){
            clearInterval(intervalId)
            resolve(1); 
          }
       }, 1000);
   });
}

function someFunction2(){
   return new Promise(resolve => {
       let i = 0;
       const intervalId = setInterval(() => {
          i++;
          console.log("someFunction2", i);
          if(i == 5){
            clearInterval(intervalId)
            resolve(2); 
          }
       }, 1000);
   });
}

(async function(){
   const result = await Promise.all([someFunction1(),someFunction2()]);
   console.log("result",result);
})();

系列

function someFunction1(){
   return new Promise(resolve => {
       let i = 0;
       const intervalId = setInterval(() => {
          i++;
          console.log("someFunction1", i);
          if(i == 5){
            clearInterval(intervalId)
            resolve(1); 
          }
       }, 1000);
   });
}

function someFunction2(){
   return new Promise(resolve => {
       let i = 0;
       const intervalId = setInterval(() => {
          i++;
          console.log("someFunction2", i);
          if(i == 5){
            clearInterval(intervalId)
            resolve(2); 
          }
       }, 1000);
   });
}

(async function(){
   const result = [await someFunction1(),await someFunction2()];
   console.log("result",result);
})();

两者给予了完全相同的 * 结果 *,但到达那里是非常不同的。

mv1qrgav

mv1qrgav5#

Promise.all()的MDN文档指出
此方法可用于聚合多个承诺的结果。通常在存在多个相关异步任务(整个代码依赖这些任务成功工作)时使用-在代码继续执行之前,我们希望完成所有这些任务。
虽然它不是显式的,但是您可以等待Promise.all跟踪多个承诺,只有当所有承诺都得到解决时,代码才会继续执行。
由于await的操作方式不同,您提到的在数组中捕获单独异步任务的另一种方法也不相同。
await分割执行流,允许异步函数的调用方继续执行。在await延迟异步函数的继续之后,后续语句的执行继续进行。如果此await是其函数执行的最后一个表达式,则通过向函数的调用方返回完成await函数的挂起Promise并继续执行该调用方,继续执行。
所以,每次等待都将暂停执行,然后再继续。不需要演示。

相关问题