JavaScript 中 FileReader 的 async/await 问题

Problem with async/await with FileReader in JavaScript

我在 Vue.js 项目中使用 FileReader,但我遇到以下代码问题:

async uploadDocuments(files) {
    for (let file of files) {
        let fileName = file.name;
        let fileContent;
        let reader = new FileReader();
        reader.onload = async () => {
            fileContent = reader.result;
            await this.submitFile(fileContent, fileName, fileType)
                .then(/* THEN block */)
                .catch(/* CATCH block */);
        };
        reader.onerror = (error) => { console.warn(error); };
        reader.readAsDataURL(file);
    }
    console.log("COMPLETED");
}

async submitFile(fileContent, fileName, fileType) {
    // this function should handle the file upload and currently contains a timeout
    await new Promise((resolve) => setTimeout(resolve, 3000));
}

这是所需的执行顺序(包含两个文件的示例):

  1. (等待 3 秒)
  2. THEN 块(文件 1)
  3. (等待 3 秒)
  4. THEN 块(文件 2)
  5. 完成

但这是实际的执行顺序:

  1. 完成
  2. (等待 3 秒)
  3. 然后块
  4. 然后块

“THEN 块”在超时后正确执行,但是 for 循环中的代码继续执行,而不等待 onload 函数的执行。

如何使 reader 异步?我尝试了很多解决方案(例如将 for 循环包装在一个承诺中并将 resolve() 函数放在 .then() 中)但其中 none 有效。

我建议“承诺”Reader 的东西然后使用 Promise.all 直到所有文件都上传。

uploadDocuments = async (event, files) => {
  const filePromises = files.map((file) => {
    // Return a promise per file
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = async () => {
        try {
          const response = await this.submitFile(
            reader.result,
            file.name,
            fileType
          );
          // Resolve the promise with the response value
          resolve(response);
        } catch (err) {
          reject(err);
        }
      };
      reader.onerror = (error) => {
        reject(error);
      };
      reader.readAsDataURL(file);
    });
  });

  // Wait for all promises to be resolved
  const fileInfos = await Promise.all(filePromises);

  console.log('COMPLETED');

  // Profit
  return fileInfos;
};

试试这个。

reader.onload 之前添加 await 它将保持到那时或 catch 块执行成功

async uploadDocuments(event) {
    for (let file of files) {
        let fileName = file.name;
        let fileContent;
        let reader = new FileReader();
        await reader.onload = async () => {
            fileContent = reader.result;
            await this.submitFile(fileContent, fileName, fileType)
                .then(/* THEN block */)
                .catch(/* CATCH block */);
        };
        reader.onerror = (error) => { console.warn(error); };
        reader.readAsDataURL(file);
    }
    console.log("COMPLETED");
}

async submitFile(fileContent, fileName, fileType) {
    // this function should handle the file upload and currently contains a timeout
    await new Promise((resolve) => setTimeout(resolve, 3000));
}```