核心目标是避免主线程卡顿,而非加快磁盘读取;将解析、校验、转换等操作移至Web Worker,配合readAsArrayBuffer()分块移交、零拷贝、结构化输出、渐进通信及错误兜底与缓存机制。

Worker 线程处理大型文件流读取,核心目标不是“更快读磁盘”,而是让主线程不卡——真正拖慢页面的,是读完之后立刻做的解析、校验、转换这些事。把它们挪进 Worker,滚动、输入、动画才能保持流畅。
分块移交 ArrayBuffer,避免整文件加载
别用 FileReader.readAsText() 或 readAsDataURL():前者要转字符串再解析,慢且内存暴涨;后者 base64 编码会让体积增加 33%,纯属自找麻烦。正确做法是用 readAsArrayBuffer() 获取原始二进制,再按需分块移交:
- 对 JSONL(每行一个 JSON):主线程按换行符切分 ArrayBuffer,每次只传一块给 Worker 解析单行
- 对 Excel(.xlsx):主线程读完整 ArrayBuffer 后,用
postMessage(buffer, [buffer])零拷贝移交,Worker 内直接调 SheetJS - 对自定义二进制协议:主线程先读前 8KB 判定帧头,再按需读后续段落,逐块移交,Worker 累积缓冲+状态机识别边界
Worker 内解析要轻量、可中断、结构化输出
Worker 不是万能黑盒,写错一样卡死或爆内存。关键控制点有三个:
- 跳过非必要字段:比如解析 Excel 时传
{ cellDates: true, dateNF: 'yyyy-mm-dd', bookVBA: false, cellStyles: false },关掉样式、宏、图表 - 只输出有用结构:不要返回原始 ZIP 流或 XML 字符串,Worker 应直接输出扁平数组,例如
[{name: "A", value: 123}, ...] - 支持中途取消:主线程发
{ type: 'abort' }消息,Worker 内用布尔标记 + 循环检查,及时退出长耗时逻辑
通信不传大对象,只传有用数据
postMessage 不是快递车,别把几万条记录打包塞进去。传输效率取决于你传什么:
- 数值列多?转成
Float32Array或Uint32Array,比对象数组省内存、快解析 - 必须传结构化对象?用
structuredClone()替代JSON.stringify/parse,支持 Date、Map、Set - 结果太多一次传不完?Worker 按每 2000 条一组
postMessage,主线程用requestIdleCallback批量渲染,防重绘抖动
错误兜底与缓存协同,提升体验稳定性
用户不关心你用了几个线程,但会在意“点了没反应”或“点两次跑两遍”:
- 所有异常(损坏 ZIP、加密 Excel、非法 UTF-8)都
catch住,统一postMessage({ error: 'xxx' }),主线程弹提示而非白屏 - 对已解析过的文件哈希做缓存判断,相同内容跳过重复解析;Worker 完成后主动
terminate(),避免内存泄漏 - 结合
navigator.hardwareConcurrency动态建 Worker 池,数量建议不超过 CPU 核心数的 2 倍


















