【问题标题】:Why to use .then() rather than async/await inside loop that returns promise?为什么在返回 promise 的循环内使用 .then() 而不是 async/await?
【发布时间】:2021-05-21 18:53:01
【问题描述】:

我遇到了多篇关于如何正确地将新 Promise 从循环中推送新 Promise 的文章,该循环在新 Promise 中执行多个 API 调用到一个数组中。
返回的 Promise 中的代码应该连续运行,并且在循环之后代码应该只在数组中的所有 Promise 都被解析后才继续运行(因此我使用Promise.all())。

对我来说很直观的版本:

const returnPromisesAsyncAwait = async () => {
  let pArray = []

  for (let i = 1; i <= 5; i++) {
    pArray.push(
      // Is this antipattern?
      new Promise(async (resolve, reject) => {
        console.log('Entered promise' + i)
        await new Promise((res) => setTimeout(res, i * 100))
        console.log('Finished promise 1 inside promise' + i)
        await new Promise((res) => setTimeout(res, i * 500))
        console.log('Finished promise 2 inside promise' + i)
        resolve(true)
      })
    )
  }

  await Promise.all(pArray)
  console.log(pArray)
  console.log('Done!')
}

returnPromisesAsyncAwait()

此代码返回的输出与第二个应该是模式正确的输出完全相同:

const returnPromisesThen = async () => {
  let pArray = []

  for (let i = 1; i <= 5; i++) {
    pArray.push(
      // Is this antipattern?
      new Promise((resolve, reject) => {
        console.log('Entered promise' + i)
        new Promise((res) => setTimeout(res, i * 100)).then(() => {
          console.log('Finished promise 1 inside promise ' + i)
          new Promise((res) => setTimeout(res, i * 500)).then(() => {
            console.log('Finished promise 2 inside promise ' + i)
            resolve(true)
          })
        })
      })
    )
  }

  await Promise.all(pArray)
  console.log(pArray)
  console.log('Done!')
}

returnPromisesThen()

在这种情况下,有什么理由让我们宁愿使用 .then() 语法而不是 async/await 语法?

【问题讨论】:

  • 你想读什么?
  • 文章发表了多长时间?在 async/await 存在之前,互联网上有很多文章,但是,仅仅因为 async/await 存在并不意味着以前的实现方式无效。

标签: javascript loops async-await promise es6-promise


【解决方案1】:

在您的示例中,两个代码将导致相同的行为。所以用 async/await 就好了。

循环内的风险是顶级等待;例如

for (let i = 1; i <= 5; i++) {
    await fetch();
}

这样做会暂停循环,直到每个承诺解决。这将导致性能问题,因为所有承诺都会以串行方式解决。这通常是一种糟糕的模式,因为它违背了异步调用的目的。

如果你只在你的 Promise 回调中使用 async/await,那就没问题了。

另一个类似的常见问题是等待多个呼叫彼此相邻而不是使用Promise.all()

- const a = await fetchA();
- const b = await fetchB(); // Here fetchB doesn't start until fetchA complete.

+ const [a, b] = Promise.all([
+     fetchA(),
+     fetchB(),
+ ]);

【讨论】:

    【解决方案2】:

    我通过将循环内的代码放入外部异步函数中解决了“问题”,因此我不会遇到将异步函数添加到新承诺的问题。

    asyncProcess = async (i) => {
      console.log('Entered promise' + i)
      await new Promise((res) => setTimeout(res, i * 100))
      console.log('Finished promise 1 inside promise' + i)
      await new Promise((res) => setTimeout(res, i * 500))
      console.log('Finished promise 2 inside promise' + i)
    }
    
    const returnPromiseWithExternalProcess = async () => {
      let pArray = []
    
      for (let i = 1; i <= 5; i++) {
        pArray.push(asyncProcess(i))
      }
    
      await Promise.all(pArray)
      console.log(pArray)
      console.log('Done!')
    }
    
    returnPromiseWithExternalProcess()

    【讨论】:

      猜你喜欢
      • 2019-08-17
      • 2017-09-11
      • 2019-12-14
      • 2021-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-22
      相关资源
      最近更新 更多