必须用 worker 做大文件哈希:将 cpu 密集型计算移出主线程,避免页面冻结;结合分片与多 worker 并行(≤hardwareconcurrency),实测 1.67gb 文件提速 6 倍以上,并通过 arraybuffer 零拷贝、进度反馈和容错机制保障性能与体验。

用 Worker 做大文件哈希,核心就一条:把 CPU 密集型计算从主线程搬出去,避免页面卡死。几百 MB 甚至上 GB 的文件,直接在主线程算 SHA-256 或 MD5,用户点不动、滑不了、甚至整个页面“冻结”,不是代码写得不好,而是 JS 单线程扛不住。
为什么必须用 Worker?
浏览器主线程既要渲染 UI、响应点击、处理动画,又要算哈希——三者抢同一个 CPU 时间片,必然互相拖累。Worker 在独立线程运行,不共享主线程堆栈和 DOM,天然解耦。尤其对视频、镜像、数据库备份这类大文件,计算过程动辄数秒到数十秒,不用 Worker 就等于放弃用户体验。
- 主线程阻塞 → 页面假死、交互无响应、动画掉帧
- Worker 独立运行 → 哈希照算,滚动、按钮点击、输入框输入全都不受影响
- 现代设备多核普遍(navigator.hardwareConcurrency 通常为 4–16),Worker 能真正利用起来,不是“伪并发”
分片 + 并行:提速的关键组合
单纯用一个 Worker 串行算整文件,只是把卡顿从主线程移到后台线程,总耗时没变。真正提速靠的是“分片 + 多 Worker 并行”:
- 按固定大小切片(如 2–5 MB/片),最后一片不足也单独处理
- 启动多个 Worker(数量建议 ≤ navigator.hardwareConcurrency,通常 4 个较稳)
- 每个 Worker 分配连续几片(比如 Worker A 算第 0–3 片,Worker B 算第 4–7 片),避免频繁创建销毁开销
- 各 Worker 内部用 crypto.subtle.digest('SHA-256', arrayBuffer) 计算每片哈希,再拼接所有片哈希值做一次最终哈希
实测显示:1.67 GB 文件,串行计算需 18 秒;4 Worker 并行分片后,总时间压缩至约 3 秒,提速 6 倍以上。
数据传递与内存安全
Worker 间不能直接传 File 对象或 Blob,必须转成可转移的 ArrayBuffer,否则会触发深拷贝,内存暴涨甚至 OOM:
- 主线程读取文件用 file.arrayBuffer()(注意超大文件慎用,可改用 ReadableStream + BYOBReader 分批读)
- 传给 Worker 时使用 worker.postMessage(data, [arrayBuffer]) 实现零拷贝传输
- Worker 收到后直接 slice 子 buffer,无需额外复制;计算完立即释放引用,防止内存堆积
- 任务结束务必调用 worker.terminate(),避免线程残留和内存泄漏
进度反馈与容错设计
用户需要知道“还在算,没卡住”。Worker 可通过 postMessage({ type: 'progress', loaded: bytesDone, total: fileSize }) 实时回传进度,主线程据此更新 UI 进度条。同时建议加入简单容错:
- Worker 内部加 try/catch,出错时 postMessage({ type: 'error', message: '...' })
- 主线程监听超时(如 30 秒未响应),主动 terminate 并提示重试
- 对关键业务(如秒传校验),可额外保存中间哈希结果到 IndexedDB,断网恢复后续算











