Promise.all 和 .map 函数的异步/等待无法按预期工作

Posted

技术标签:

【中文标题】Promise.all 和 .map 函数的异步/等待无法按预期工作【英文标题】:Async/Await not working as expected with Promise.all and a .map function 【发布时间】:2017-08-28 20:59:51 【问题描述】:

我正在使用大量 async 函数,但遇到了一个奇怪的问题。

我的代码正在运行,如下所示:

async mainAsyncFunc (metadata) 
  let files = metadata.map(data => this.anotherAsyncFunc(data.url));
  return Promise.all(files);

anotherAsyncFunc 函数看起来像:

  async anotherAsyncFunc (url) 
    return await axios(
      url,
    ).then(res => res.data)
      .catch(err => 
      throw err;
    );
  

当我尝试将更多数据附加到第一个函数 (mainAsyncFunc) 返回的内容时,我的问题就出现了。我的想法是在map 中自然而然地做到这一点,当一切都说完了,修改它看起来像:

async mainAsyncFunc (metadata) 
    files = metadata.map(data => 
        return new Promise((resolve) => 
          let file = this.anotherAsyncFunc(data.download_url);
          let fileName = data.name;
          resolve(
            file,
            fileName
          );
        );
      );
    return Promise.all(files);

如果不清楚,我会像往常一样获取文件本身,并为其附加一个文件名,然后解析该对象。

由于某种原因,这将返回一个待处理的 Promise,而我希望它等待它们被实现,然后作为对象中的完整文件和名称返回。任何帮助理解我做错了什么将不胜感激。

【问题讨论】:

async 函数返回承诺。你也不能将一个 Promise 包装的值变成一个普通的值,你总是需要await 或调用.then。你为什么期望得到一个数组? @JaredSmith 我使用Promise.all(),因为我正在映射数据集并为每个项目返回异步函数的结果。从而创建一个数组。但是,我刚刚解决了自己的问题,现在正在发布解决方案 Promise.all 返回一个 Promise。同样,您不能“解开”承诺。你只能.then它。 @JaredSmith 我可以向您保证,我的工作代码正在返回一个已完成对象的数组:)。如果它可以帮助您更好地理解它,我将这个函数称为:FileRetriever.mainAsyncFunc(metadata).then(contents => ...),而我的新工作代码contents 是一个数组。 不,不是,你的代码不像你想象的那样工作。 await.then 上的糖。你永远无法解开承诺。在一般情况下,这在逻辑上是不可能的,因为 没有办法 来判断一个承诺是否已解决。 【参考方案1】:

看来你的问题已经解决了,只是一个指针,你可以进一步简化你的代码如下:

async anotherAsyncFunc (url) 
    return (await axios( url )).data;


async mainAsyncFunc (metadata) 
    let files = metadata.map(async data => (
        file: await this.anotherAsyncFunc(data.download_url),
        fileName: data.name
    ));

    return Promise.all(files);

【讨论】:

【参考方案2】:

刚刚解决了这个问题:

  files = metadata.map(async (data) => 
    let file = await this.anotherAsyncFunction(data.download_url);
    let fileName = data.name;
    return 
      file,
      fileName
    ;
  );

我需要将匿名函数包装在async 中,这样我就可以在其中使用await。希望这可以帮助其他有类似问题的人!

【讨论】:

以上是关于Promise.all 和 .map 函数的异步/等待无法按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

如何使用Promise.All()执行异步诺言?

promiseall退出条件

Promise 异步函数顺序执行

promise.all 解说

深深感受 Promise.all 带来的速度提升

了解 Promise.all 和 Array.map()