Web Worker是浏览器提供的绕过JS单线程瓶颈的机制,用于将CPU密集型任务移出主线程以避免卡顿;它无DOM访问能力,仅支持纯计算与有限I/O,通过postMessage通信。

Web Worker 不是“让 JS 变成多线程语言”,而是浏览器给前端提供的合法绕过单线程瓶颈的机制。学它不是为了炫技,而是为了解决一个具体问题:当计算一卡,用户就走——你得把重活搬出主线程。
先搞清主线程到底在忙什么
主线程干四件事,且全挤在一条线上:
- 执行 JavaScript(你的业务逻辑、框架更新、数据处理)
- 解析 HTML/CSS、计算样式、布局(Layout)、绘制(Paint)
- 响应用户操作(点击、滚动、输入、触摸事件)
- 运行定时器、处理 fetch 回调、做垃圾回收
只要其中一项耗时超过 50ms,用户就能明显感知卡顿;超过 100ms,FID(首次输入延迟)就超标。比如遍历 10 万条数据做字符串匹配,主线程一算就是 900ms,期间滚动条冻结、输入框失焦、按钮点不动——这不是代码写得差,是执行位置错了。
Web Worker 能做什么、不能碰什么
Worker 是一个独立的 JS 执行环境,但它没有 DOM、没有 window、没有 document、不能 alert、不能读 localStorage。它能做的,是纯计算和有限 I/O:
- ✅ 运行 CPU 密集型任务:排序、加密、图像像素处理、路径规划、JSON 解析/序列化大数组
- ✅ 发起 fetch 或 XMLHttpRequest(注意:不能带 cookie,除非配置 credentials)
- ✅ 使用 FileReader 读取文件内容(配合 input[type=file])
- ✅ 操作部分 IndexedDB API(仅支持事务内只读查询)
- ❌ 不能修改任何页面元素,不能监听 click 或 scroll,不能访问 URL 参数或 history
换句话说:Worker 是“计算员”,主线程是“指挥+演员”。两者各司其职,靠消息来回传指令和结果。
通信不是共享内存,而是邮局式投递
主线程和 Worker 之间不共享变量,不共用内存地址,不直接调用函数。所有交互都靠 postMessage() + onmessage,数据会自动结构化克隆(深拷贝)。这意味着:
- 传大对象(如 10MB JSON)会有明显序列化/反序列化开销,建议传 ID 或分片数据
- 无法传递函数、undefined、Symbol、Date 对象(会被转为 null),推荐只传 plain object、Array、Number、String、Boolean
- 高频小消息(如每帧发一次坐标)不如合并后批量发送,避免通信风暴
- 可以用
Transferable(如 ArrayBuffer)实现零拷贝传输,大幅提升大数据吞吐效率
从写第一个 Worker 到工程化落地
不要一上来就封装类库,先跑通最小闭环:
- 新建
worker.js文件,用self.onmessage接收,self.postMessage返回 - 主线程用
new Worker('worker.js')创建,检查window.Worker兼容性 - 加
worker.onerror监听错误,否则 Worker 崩溃无声无息 - 任务结束及时调用
worker.terminate(),避免内存泄漏 - 进阶可尝试 Blob URL Worker(动态生成脚本)、Module Worker(
new Worker('x.js', {type: 'module'}))、或结合 Comlink 简化通信逻辑
真实项目中,Worker 常用于搜索预处理、PDF 文本提取、实时音视频元数据解析、离线地图瓦片计算等场景——它们共同点是:计算可离线、结果可缓存、过程不依赖 UI 状态。











