为何异步循环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解决该问题,但想明确两个问题:
- 为什么添加这段处理代码会导致主线程阻塞?
- 是否存在比
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
相关产品推荐
相关产品推荐

