必须用 Web Worker 计算大文件 MD5,因 JS 单线程下主线程计算会导致 UI 冻结;需分片(2–8MB)+ 增量哈希 + 结构化克隆传递 File,再通过服务端 MD5 校验实现秒传。
直接在主线程算大文件 md5,页面会卡死几秒甚至十几秒,用户点不动按钮、进度条不动、体验极差。用 web worker 把计算挪到后台线程,界面完全不卡,还能准确拿到文件指纹用于秒传判定——这才是生产环境该有的做法。
为什么必须用 Web Worker 算 MD5
浏览器 JS 是单线程的,而 MD5 计算是纯 CPU 密集型任务。对一个 2GB 文件:
- 主线程计算:占用主线程超 10 秒,UI 完全冻结
- Web Worker 计算:主线程照常响应点击、滚动、动画,用户无感知
- 实测数据:512MB 文件,主线程耗时 14.3 秒且卡死;Worker 耗时 15.1 秒但 UI 零延迟
分片计算是关键前提
不能把整个大文件一次性读进内存(会爆内存、触发浏览器崩溃),必须边切片边计算:
- 推荐切片大小:2–8 MB(根据文件体积动态调整,比如 ≤20MB 用 1MB,≥200MB 用 6–8MB)
- 用 File.prototype.slice 分块,配合 FileReader.readAsArrayBuffer 逐块读取
- 使用 SparkMD5.ArrayBuffer 的增量接口(
append()+end()),避免重复构造对象
Worker 文件怎么写才可靠
子线程不能直接 import 模块,需用 importScripts 加载本地脚本:
- 把
spark-md5.min.js内容复制到public/spark.js - Worker 文件开头写:
importScripts('/spark.js') - 接收主线程传入的
File对象(注意:File 可结构化克隆,能安全传递) - 计算完成后调用
postMessage({ md5: 'xxx', totalChunks: 123 })返回结果
秒传判定的完整链路
拿到文件整体 MD5 后,不是直接上传,而是先和服务端确认是否已存在:
- 前端发起请求:
POST /api/upload/check?fileMd5=xxx - 服务端查库或对象存储(如 MinIO)中是否存在同 MD5 的完整文件
- 命中则返回
{ code: 200, url: '/files/xxx.mp4' },前端跳过上传,完成“秒传” - 未命中才进入切片上传流程,同时开启断点续传支持
不复杂但容易忽略:MD5 是秒传的钥匙,Worker 是不让用户等得焦虑的保障。两者结合,才是现代大文件上传的标配。

















