最有效解决页面卡顿的方式是将CPU密集型任务移至Web Workers。判断标准为单次执行是否超16ms,典型任务包括图像处理、大数据解析、加密运算、矩阵计算、二维码生成等;需用transfer list实现零拷贝通信;必须监听onerror并规范Worker生命周期;避免频繁新建,推荐使用Worker Pool复用。

直接把 CPU 密集型任务从主线程移出去,是解决页面卡顿最有效的方式。Web Workers 不是“让计算更快”,而是让计算彻底不干扰 UI 渲染和用户操作——只要单次执行预期超过 16ms,就该交给 Worker。
哪些任务必须卸载到 Worker
判断标准很明确:是否能在一帧(约 16ms)内完成。不能,就必须移出主线程。典型场景包括:
- 图像像素级处理(Canvas 滤镜、缩略图生成、水印叠加)
- 万行以上 CSV/JSON 的解析、排序或聚合
- SHA-256、AES 加解密、RSA 签名验签
- 大矩阵运算、物理模拟、素数筛、斐波那契递归(n > 40)
- 二维码/条形码生成、PDF 文本提取、OCR 前端预处理
通信要快,更要零拷贝
传 10MB 图像数据时,用普通 postMessage(data) 会触发深拷贝,序列化可能耗时上百毫秒——反而更卡。关键在转移所有权:
- 主线程发送时带上 transfer list:worker.postMessage({ buffer }, [buffer]),之后 buffer 自动变 null
- Worker 内直接使用该 ArrayBuffer,无复制开销
- 仅支持 ArrayBuffer、ImageBitmap、MessagePort 等可转移类型
- 避免传深层嵌套对象,优先用 TypedArray 或扁平结构
错误不能静默,生命周期必须可控
Worker 报错默认不通知主线程,UI 可能一直转圈却毫无提示:
- 主线程创建时监听 worker.onerror,捕获加载失败或初始化异常
- Worker 脚本顶部加 self.onerror = e => self.postMessage({ type: 'error', error: e.message })
- 路径必须同源;Vite/Webpack 项目需声明 { type: 'module' },否则 import 失败
- 禁用 data: URL 或内联脚本创建方式,主流浏览器已拦截
别为小任务反复新建 Worker
每次 new Worker() 都有启动开销,高频小任务反复创建得不偿失:
- 用 Worker Pool 管理固定数量实例(建议 ≤ navigator.hardwareConcurrency)
- 每个 Worker 复用处理多个请求,靠 message.type 区分任务类型
- 主线程发任务时附带 timeout ID,Worker 超时未响应则主动终止并通知重试
- 长期空闲 Worker 可调用 worker.terminate() 释放资源
不复杂但容易忽略。

















