必须将文件切片和md5计算移至web worker执行以避免主线程卡死;主线程负责分片读取与调度,worker用sparkmd5增量计算哈希并回传,配合并发控制和内存释放实现高效稳定的秒传支撑。

直接在主线程里切片加算 MD5,页面会卡死几秒甚至十几秒,用户点不动、进度条不动、体验极差。必须把这两件事挪到 Web Worker 里做——切片是读取动作,MD5 是纯 CPU 运算,都适合后台线程处理。
Worker 文件要能独立运行
新建一个 md5-worker.js(后缀不重要,但路径要对),开头用 importScripts 加载 SparkMD5:
- 把
spark-md5.min.js内容复制到public/spark.js,再在 worker 开头写importScripts('/spark.js') - 监听主线程发来的文件对象或 ArrayBuffer:
self.onmessage = ({ data }) => { ... } - 收到后用
SparkMD5.ArrayBuffer.hash(data.buffer)直接算单片哈希;若需算整个文件,则用append()+end()增量拼接 - 计算完立刻
postMessage({ id: 2, hash: 'xxx', total: 12 })回传,带唯一标识方便主线程匹配
主线程负责分片、派发与组装
不用一次性读整个文件,而是边切边读、边读边发:
- 用
file.slice(start, end)切出 Blob,推荐片大小:≤20MB 用 1–2MB,≥200MB 用 6–8MB - 每个分片用
FileReader.readAsArrayBuffer()读成 ArrayBuffer,读完立即worker.postMessage({ id: i, data: buffer }) - 主线程用数组或 Map 缓存结果,等全部返回后,拼出完整文件 MD5 和各分片 MD5 列表
- 读完记得手动释放内存:
buffer = null,帮浏览器 GC 回收
并发控制和复用更稳
别为每片新建 Worker,也别让所有片一股脑全塞进去:
- Worker 实例创建一次,重复调用
postMessage即可,避免频繁启停开销 - 限制同时计算的分片数(比如最多 3 个),可用 Promise 队列或
Promise.allSettled控制节奏 - 大文件可按浏览器线程数拆任务:
navigator.hardwareConcurrency || 4,分配不同分段给不同 Worker 并行跑 - 若需实时进度,Worker 内部每算完一片就发一次
{ progress: 30 },主线程累加更新 UI
不复杂但容易忽略:切片是手段,MD5 是凭证,Worker 是保障。三者串起来,才能既快又稳地支撑秒传和断点续传。











