【问题标题】:Using Async/Await vs Promise.all with for-loops将 Async/Await 与 Promise.all 与 for 循环一起使用
【发布时间】:2020-09-24 23:08:32
【问题描述】:

这是我目前的理解:

for 循环中的 async/await 应该暂停执行,直到 promise 解决,这意味着循环的下一次迭代在该行完成之前不会发生。

考虑以下数组:

const data = [];
for (let i = 0; i <= 100000; i++) {
    data.push(i);
}

方法一:在for循环中等待Promise

async function method1() {
  const startTime = new Date();
  console.log('start:', startTime);

  for (const item in data) {
    await new Promise(resolve => {
      if (item % 3 === 0) {
        resolve({});
      } else {
        resolve(item)
      }
    });
  }

  const endTime = new Date();
  console.log('finish:', endTime);
  console.log('total time:', endTime-startTime);
}

因为它需要顺序执行 Promise 才能继续循环,所以我认为使用 Promise.all 将是一种性能增强,可以在更大程度上利用异步处理:

方法 2:Promise.all 跟随 for 循环

async function method2() {
  const promises = [];
  const startTime = new Date();
  console.log('start:', startTime);

  for (const item in data) {
    const promise = new Promise(resolve => {
      if (item % 3 === 0) {
        resolve({});
      } else {
        resolve(item)
      }
    });

    promises.push(promise);
  }

  await Promise.all(promises);
  const endTime = new Date();
  console.log('finish:', endTime);
  console.log('total time:', endTime-startTime);
}

我的推理:当每个先前创建的 Promise 尝试解决时,循环将继续发出新的 Promise。所以在我看来,方法 1 = 阻塞......而方法 2 = 更少阻塞。

当我在 repl.it 上运行它们时,我发现方法 1 实际上更快,几乎快了 2 倍。有人可以解释为什么会这样吗?不应该反过来吗?

【问题讨论】:

  • 这两种方法在概念上的区别在于,一种并行运行异步操作,另一种串行运行它们。使用虚假的异步操作,您看不到这种差异的真正效果。使用真正的异步操作,效果会很明显,并且并行运行会有更快的端到端时间。如果每个异步操作都需要 200ms 来解析,那么方法 1 将在 ~n * 200ms 中解析,而方法 2 将在 ~200ms 中解析,其中 n 是您运行的异步操作的数量。

标签: javascript node.js asynchronous promise async-await


【解决方案1】:

我的猜测是你解析太快了,所以循环支配了执行时间,因为method2有两个循环:一个推入数组,一个promise.all完成,而method1只有一个循环,所以你的感觉“几乎是两倍”实际上在理论上是正确的。

尝试像new Promise(resolve =&gt; setTimeout(resolve, 200)) 那样伪装actual async operation,你应该会得到你所期望的

【讨论】:

  • 工作就像一个魅力。我想尝试用同步操作来测试异步进程并没有什么意义吧
  • @stoneb 虽然您的代码解析了一个非异步值,但您的代码也是异步的,只是“异步”部分发生得太快了
【解决方案2】:

进一步补充 Drake 所说的话。方法 2 在没有超时的情况下速度较慢的唯一原因是它必须遇到的循环数,但在请求或异步操作有延迟的实际场景中。方法 2 在大多数情况下会更快

这是修改后的带有 SetTimeout 的 sn-p。

const data = [];
for (let i = 0; i <= 1000; i++) {
    data.push(i);
}


async function method1() {
  const startTime = new Date();
  console.log('start 1:', startTime);

  for (const item in data) {
   await new Promise(resolve => {
      setTimeout(()=>{
        if (item % 3 === 0) {
        resolve({});
      } else {
        resolve(item)
      }
      },1)
    });
  }
  const endTime = new Date();
  console.log('finish 1:', endTime);
  console.log('total time:', endTime-startTime);
}

async function method2() {
  const promises = [];
  const startTime = new Date();
  console.log('start 2:', startTime);

  for (const item in data) {
    const promise = new Promise(resolve => {
      setTimeout(()=>{
        if (item % 3 === 0) {
        resolve({});
      } else {
        resolve(item)
      }
      },1)
    });

    promises.push(promise);
  }

  await Promise.all(promises);
  const endTime = new Date();
  console.log('finish 2:', endTime);
  console.log('total time:', endTime-startTime);
}

method1()
method2()

【讨论】:

  • 感谢您的代码块。这澄清了很多事情!
猜你喜欢
  • 2021-02-27
  • 1970-01-01
  • 2022-06-23
  • 2019-03-12
  • 1970-01-01
  • 2017-11-05
  • 2019-04-15
  • 2014-06-19
相关资源
最近更新 更多