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

为何异步循环File.stream().getReader().read()会阻塞主线程?

文件流处理时主线程阻塞的原因及优化方案

原始可运行代码

HTML部分

<input type="file" id="el">
<code id="out"></code>

JavaScript部分

const el = document.getElementById('el');
const out = document.getElementById('out');
el.addEventListener('change', async () => {
  const file = el.files?.[0];
  if (file) {
    const reader = file.stream().getReader();
    out.innerText = JSON.stringify({ fileSize: file.size });
    let received = 0;
    while (true) {
      const chunk = await reader.read();
      if (chunk.done) break;

      // chunk.value.forEach((it) => it + 1);

      received += chunk.value.byteLength;
      out.innerText = JSON.stringify({
        fileSize: file.size,
        process: `${received} / ${file.size} (${((received / file.size) * 100).toFixed(2)}%)`,
      });
    }
  }
});

问题现象

上述代码原本可正常运行,<code>标签能实时显示文件读取进度。但取消注释chunk.value.forEach((it) => it + 1);这行后(这是实际MD5计算逻辑的简化代码),Edge 125浏览器中出现主线程阻塞,页面在文件处理完成前完全停止响应。

目前我可以通过requestAnimationFrame解决该问题,但想明确两个问题:

  1. 为什么添加这段处理代码会导致主线程阻塞?
  2. 是否存在比requestAnimationFrame更优的解决方案?

补充测试说明

测试发现浏览器似乎会限制每个chunk的大小,使得每次循环的耗时维持在16ms左右,额外的处理代码几乎不影响单chunk的处理耗时和chunk大小:

while(true) {
  const start = Date.now();
  // ... 读取chunk及处理逻辑
  console.log('chunk', Date.now() - start, chunk.value.byteLength);
}

输出日志示例:

chunk 7 524288
chunk 17 1572864
chunk 25 2097152
chunk 16 2097152
chunk 18 2097152
chunk 15 2097152
chunk 16 2097152
...

内容的提问来源于stack exchange,提问作者DisLido

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 17:18:17