必须用 web worker 计算哈希以避免主线程卡顿,因大文件哈希会阻塞 ui;需通过 transferable 实现 arraybuffer 零拷贝传递;分片大小建议 2–5mb,前后端哈希逻辑须严格一致;哈希结果支撑秒传判定、断点续传与分片校验。

大文件上传时卡顿,本质是主线程被哈希计算拖住。用 Web Worker 把 MD5(或 SHA256)这类耗时运算挪到后台线程,UI 保持响应,这是必须做的一步,不是可选项。
为什么必须用 Web Worker 算哈希
一个 2GB 文件在主线程调用 spark-md5 或 crypto.subtle.digest 逐块读取计算,会持续占用 CPU 数秒甚至数十秒。期间页面完全无响应:按钮点不动、滚动卡死、动画冻结。用户感知就是“页面崩了”。Web Worker 提供独立执行环境,不共享内存、不阻塞渲染,天然适合这种纯计算任务。
File → ArrayBuffer 零拷贝传递是关键
Worker 接收文件不能直接传 File 对象——它无法序列化,会变成空对象。正确做法是:
- 主线程用
file.arrayBuffer()或file.slice().arrayBuffer()获取底层二进制数据 - 用
postMessage(arrayBuffer, [arrayBuffer])第二个参数传入 transferable 列表,实现零拷贝移交 - Worker 内直接操作
Uint8Array,避免重复内存分配
漏掉 [arrayBuffer] 这个 transfer list,数据就会被结构化克隆,大文件复制一次就吃光内存,还拖慢速度。
分片策略与哈希拼接要严格一致
秒传依赖哈希唯一性,前后端算法必须对齐。常见错误是分片大小不统一或拼接逻辑错位:
- 推荐分片大小设为 2–5MB(如
5 * 1024 * 1024),太小增加调度开销,太大削弱并发收益 - Worker 中按顺序读取每个分片的 ArrayBuffer,用
spark-md5的append()累积哈希,或先算各分片哈希再二次聚合(如拼接后整体再哈希) - 务必保证前端分片逻辑和服务端校验逻辑完全一致——包括起始偏移、边界处理、编码方式
结合断点续传与秒传的流程闭环
哈希不只是为了“不卡”,更是整个上传智能控制的起点:
- 先算出完整文件 Hash,立刻请求服务端检查是否存在(秒传判定)
- 若未命中,再发起
/upload/progress?hash=xxx查询已上传分片列表 - 跳过已成功上传且校验通过的分片 ID,只上传缺失部分
- 上传中每个分片附带自身 Hash(可用
spark-md5.arrayBuffer(chunk)快速算),服务端做单片校验
整个过程里,Worker 只负责哈希计算;状态管理、HTTP 请求、进度更新、取消逻辑都由主线程协调,双向通信用 postMessage + onmessage 控制。











