首页 > 解决方案 > 如何在 .map 中使用多个等待?

问题描述

我知道我们不能简单地做这样的事情:

myArray.forEach(async x => await asyncOperation())

编辑:我知道这是有效的,但我需要按正确的顺序排列

如果我们必须使用异步操作遍历数组,我必须改为:

await Promise.all(myArray.map(x => asyncOperation()))

但是,我需要在同一迭代中执行两个异步操作。我知道另一种选择是只使用.reduce它看起来像这样:

await myArray.reduce((p, el) => {
      return p.then(() => {
        return somePromise(el)
          .then(res => {
            return anotherPromise(res)
          })
      })
    }, Promise.resolve())

但我正在避免嵌套承诺,并希望仅使用async/await. 所以无论如何,我的问题是,迭代需要通过两个承诺的数组的最佳等待时间是什么?

标签: javascriptasynchronousasync-await

解决方案


async/await很棒,但它们并不是所有使用承诺的代码的 100% 替代品。有时(例如,当您需要使用时Promise.all)您确实需要将承诺用作值本身,而不是在async/内部秘密使用await

一些方法可以避免这样做,比如避免使用 ES6map和其他数组迭代方法,而是使用for循环......但通常这样做是......好吧,治愈比疾病更糟糕。只需使用承诺。

编辑:

这是一个基于评论反馈的基本示例。假设您有两个(或更多)URL,并且想要获取第一个然后(在它返回之后),获取下一个,一旦它们全部被获取,就做其他事情。如果您尝试使用 ES6 数组方法同步执行此操作,即使您使用async/ await,它也不起作用:

const urls = ['www.example.com/1', 'www.example.com/2'].
var promises = urls.map(async url => await fetch(url));
Promise.all(promises).then(doSomethingElse);

该代码实际上会立即获取所有 URL;它不会等到第一个完成后才获取第二个。

为此,您可以async/awaitfor循环一起使用并避免 ES6 的东西(大概以下内容在async函数内部):

const urls = ['www.example.com/1', 'www.example.com/2'].
const pageHtml = [];
for (var i = 0; i < promises.length; i++) {
  const url = urls[i];
  const html = await fetch(url));
  pageHtml.push(html);
}
doSomethingElse(); // no need for Promise.all!

...但是您使用for的是 1999 年的循环;哎呀!我认为更好的解决方案是使用现代 Javascript,但不要将async/await用于所有内容

大多数时候使用这些关键字,但是当您需要使用Promise.all递归函数时(如果您需要“在 #2 之后获取 #1”部分;请参阅@jcubic 的答案以了解可能的实现),或者如果您不使用只是这样做:

const urls = ['www.example.com/1', 'www.example.com/2'].
var promises = urls.map(fetch);
Promise.all(promises).then(doSomethingElse);

是的,您正在避免async/await并直接使用数组或 Promise 对象Promise.all... 但是代码简短明了,可以满足您的需求。您不必总是使用这些关键字。


推荐阅读