【问题标题】:Unclear issue with Promises resolutionPromises 解决的不清楚的问题
【发布时间】:2019-11-20 15:54:41
【问题描述】:

我正在实现一个选择和下载多个文档的功能。

首先,我构建了一个对象数组,其中包含每个选定文档的名称和指向其位置的链接。

    getAllSelectedUrls = () => {
      const { selectedFiles } = this.state;

      const urls = [];
      selectedFiles.forEach((file) => {
        this.returnFileUrl(file.id).then(res => res.json()).then((data) => {
          urls.push({ fileName: file.name, url: data.content_path });
        });
      });
      return urls;
    }

returnFileUrl()是一个异步API调用,通过ID获取文件的链接:

returnFileUrl = async (fileId) => {
      try {
        const resp = await fetch(`/file?fileId=${fileId}`);
        return resp;
      } catch (err) {
        console.log(err);
      }
    }

我认为通过在.then 方法中更新urls 数组,我会确保每个url 在它返回时都会得到解决。

当我调用getAllSelectedUrls() 时,我可以在控制台中记录阵列并填充所有数据。但是,我无法遍历它或通过索引访问任何对象,大概是因为此时数据尚未解析。

【问题讨论】:

  • 是的,当您将 data.content_path 推送到数组时,它的解析就很好了。但是您的 getAllSelectedUrls 不会等待返回数组,直到所有 url 都被推送。不要使用forEach,不要使用push,而是使用Promise.all,并让getAllSelectedUrls返回一个promise。

标签: javascript reactjs promise async-await


【解决方案1】:

使用 Promise.all()

getAllSelectedUrls = () => {
      const { selectedFiles } = this.state;
      return Promise.all(selectedFiles.map(file => {
        return this.returnFileUrl(file.id)
               .then(res => res.json())
               .then(data => ({ fileName: file.name, url: data.content_path }))
      }))
      .then(urls => {

       //do whatever you need to do with the urls array

      })
      .catch(e => console.log(e))
    }

【讨论】:

  • 非常感谢您和@Bergi 的帮助:) 现在有意义
【解决方案2】:

同意@Bergi,return 不会等到异步调用完成。它立即返回一个空数组。 但是,如果 urls 数组已完全填充,您可以检查每个解析。如果是这样 - 将变量存储在某处,例如使用setState

或者只是将 urls 数组移动到状态中,每次解析只需将 url 推送到状态。

selectedFiles.forEach((file) => {
   this.returnFileUrl(file.id).then(res => res.json()).then((data) => {
      urls.push({ fileName: file.name, url: data.content_path });

      if (urls.length === selectedFiles.length) {
         this.setState({ urls });
      }
   });
});

【讨论】:

    【解决方案3】:

    试试这个:

    (已编辑)

        getAllSelectedUrls = async () => {
          const { selectedFiles } = this.state;
    
          const urls = [];
    
          for (let i = 0; i < selectedFiles.length; i++) {
              const file = selectedFiles[i];
              res = await this.returnFileUrl(file.id);
              data = await res.json();
              urls.push({ fileName: file.name, url: data.content_path });
          }
    
          return urls;
        }
    

    这样,在所有的promise都被解析并且url被推送后,函数会返回

    【讨论】:

    • 不,该函数将在 任何 url 被推送之前返回。
    • 你是对的,谢谢。我想我纠正了它,你怎么看? @Bergi
    猜你喜欢
    • 1970-01-01
    • 2022-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-06
    相关资源
    最近更新 更多