【问题标题】:Promise.all not waiting for promisesPromise.all 不等待承诺
【发布时间】:2019-09-17 23:29:38
【问题描述】:

我正在尝试将一组文件上传到 s3 存储桶。我正在为每个文件构建一组承诺,生成预签名的 URL,对文件进行 blob,然后进行上传。上传完成后,每个承诺应该解析。

当所有上传完成后,我尝试刷新页面。

我正在尝试使用以下代码执行此操作:

async function uploadFiles() {
  let requestArray = files.map(file => {
    return new Promise(resolve => {
      handleDocs.GenerateUrl(file.fileName, "{!OppName}", async (result, event) => {
        let preSignedUrl = result.Data.toString().replace(/amp;/gm, "");
        let blob = b64toBlob(file.fileString, result.ContentType);

        await fetch(preSignedUrl, {
          method: "PUT",
          body: blob,
          headers: {
            "Content-Type": result.ContentType,
          },
        });

        resolve();
      });
    });
  });

  await Promise.all(requestArray);
  document.location.reload();
}

我的猜测是handleDocs.GenerateUrl 的行为方式我不理解(它是对实际生成预签名 URL 的后端 Salesforce/APEX 服务的调用),我正在执行承诺不正确。

我找不到任何可以解决类似问题并且对我有用的示例。

实际逻辑似乎很好,因为大多数情况下文件确实上传成功。我如何建立承诺有什么问题吗?

任何帮助将不胜感激!

我意识到已经有一个关于此的问题,但根本问题似乎有所不同。

【问题讨论】:

  • 试试 Promise.all(requestArray).then(document.location.reload());
  • 抱歉,您如何确认await Promise.all(...) 在重新加载之前没有等待承诺解决?
  • @Frazer 你为什么要那样做?那里已经有一个await
  • 如果其中一个请求失败,Promise.all() 会提前返回,确保没有发生这种情况。在您的 Promise.all() 周围添加一个 try/catch
  • 旁注:let preSignedUrl = result.Data.toString().replace(/amp;/gm, "") 这是什么?你不应该是HTML解码吗?

标签: javascript promise


【解决方案1】:

我不确定实际的问题是什么,但可能会让事情更容易理解的是承诺 URL 生成:

function generateUrlP(file) {
  return new Promise(resolve =>
    handleDocs.GenerateUrl(
      file.fileName,
      "{!OppName}",
      (result, event) => resolve(result),
    ),
  );
}

async function uploadFiles() {
  const requestArray = files.map(async file => {
    const result = await generateUrlP(file);
    const preSignedUrl = result.Data.toString().replace(/amp;/gm, "");
    const blob = b64toBlob(file.fileString, result.ContentType);
    return fetch(preSignedUrl, {
      method: "PUT",
      body: blob,
      headers: {
        "Content-Type": result.ContentType,
      },
    });
  });

  await Promise.all(requestArray);
  document.location.reload();
}

【讨论】:

  • 你能解释一下为什么你认为这会表现不同吗?好像是同一个逻辑,只是换了个方向?
  • 正如我在答案的前言中所说,我不确定 OP 的实际问题是什么,但这可能更容易阅读/理解/调试。
  • 我知道你说过,我建议没有解释,这只是一个猜测,不应该是一个答案。我看不出这会有什么不同,我要求你解释一下这可能会有什么不同
【解决方案2】:

几乎可以肯定,您的问题是由单个promise 阵列失败产生的。

试试这个:

async function uploadFiles() {
  // an async function is a function that returns a promise
  let requestArray = files.map(async (file) => { 
    try {
      handleDocs.GenerateUrl(file.fileName, "{!OppName}", async (result, event) => {
        try {
          let preSignedUrl = result.Data.toString().replace(/amp;/gm, "");
          let blob = b64toBlob(file.fileString, result.ContentType);

          await fetch(preSignedUrl, {
            method: "PUT",
            body: blob,
            headers: {
              "Content-Type": result.ContentType,
            },
          });
        } catch(e){
          console.log(`Error in handleDocs`, e)
        }
      });

    } catch (e){
      console.log(`Error in requestArray`, e);
    }
  });
  await Promise.all(requestArray);
};


document.location.reload();

【讨论】:

  • 这会导致重新加载之前的await 也会抛出。我也不认为悄悄跳过文件是一个好选择。
  • 我不喜欢“几乎可以肯定”的答案,但这是我唯一能想到的。 @Akx 它正在记录错误,它并非完全静音。但是,是的,围绕整个事情进行尝试会更清楚
  • 无法实际运行代码并将所有内容放入try/catch 并找出问题所在,这是最接近解决方案的方法。另外,我想不出第一个 async 函数可以抛出错误的方法,因为一切都在 try/catch 块内。
【解决方案3】:

我想我已经找到了原因和解决方案;我只是误解了承诺的内容。

这原来是由我们正在处理的页面上的其他一些东西引起的。

我们拥有的部分功能是能够从 S3 中删除文档,这是通过调用我们编写的 API 来完成的。

作为我们测试的一部分,我们会上传一个文件,将其删除,然后重新上传,这就是我们会看到此问题的时候。

事实证明,document.location.reload(); 正在重新提交删除数据作为页面重新加载的一部分。将其更改为 window.location.href = window.location.href; 解决了我们遇到的问题。处理承诺的方式似乎没有任何问题,因此对误导性问题表示歉意。

感谢您的帮助!

【讨论】:

    猜你喜欢
    • 2021-11-28
    • 2019-09-29
    • 2019-04-29
    • 2019-05-23
    • 2019-12-10
    • 1970-01-01
    • 2021-08-29
    • 1970-01-01
    • 2013-09-16
    相关资源
    最近更新 更多