You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确等待FileReader.onload成功完成文件加载

问题根源

你的Promise写法错了:resolve(audioDict) 放在了Promise构造函数的同步代码段里,FileReader.onload和后续decodeAudioData都是异步逻辑,还没等这俩执行完,Promise就已经被标记为成功,Promise.all当然会直接走后续回调,根本等不到文件读取和解码结束。

除此之外代码还有两个容易出问题的点:

  • 没加任何错误处理:不管是FileReader读文件失败,还是音频解码失败,都没有对应的reject逻辑,出错了Promise会一直卡着没有任何提示
  • 先调用readAsArrayBuffer再绑定onload事件,极端情况(比如本地缓存文件读取速度极快)下会直接错过事件回调,导致逻辑不执行
修正代码

核心改动是把resolve挪到所有异步操作全部完成的位置,补上错误捕获,调整事件绑定顺序:

const promises = [];
// 提前初始化audioDict的数组属性,避免索引赋值报错
audioDict.filename = [];
audioDict.audio = [];
audioDict.sr = [];

for (let i = 0; i < files.length; i++) {
  promises.push(
    new Promise((resolve, reject) => {
      const fileReader = new FileReader();
      const currentFile = files[i].object;
      audioDict.filename[i] = currentFile.name;

      // 先绑定事件,再启动文件读取,避免漏触发
      fileReader.onload = (e) => {
        audioCtx.decodeAudioData(e.target.result)
          .then((decodedData) => {
            audioDict.audio[i] = {};
            for (let c = 0; c < decodedData.numberOfChannels; c++) {
              audioDict.audio[i][c] = decodedData.getChannelData(c);
            }
            audioDict.sr[i] = decodedData.sampleRate;
            // 所有处理完成后再决议Promise
            resolve(audioDict);
          })
          .catch(reject);
      };
      // 捕获文件读取错误
      fileReader.onerror = reject;
      fileReader.readAsArrayBuffer(currentFile);
    })
  );
}

Promise.all(promises)
  .then(() => {
    console.log("done!");
    // 此处可以安全访问完整的audioDict数据
  })
  .catch((err) => {
    console.error("处理失败:", err);
  });
优化建议

如果想让逻辑更不容易出错,可以不用提前按索引往全局audioDict塞数据,每个Promise处理完单个文件后直接返回当前文件的文件名、音频数据、采样率,最后在Promise.all的回调里统一组装成最终对象,能避免循环索引引用带来的偶发问题。


内容的提问来源于stack exchange,提问作者S. Yong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 11:51:12