Web Worker本质是浏览器创建的独立执行环境,与主线程内存隔离、通过消息机制通信,大对象传输可借Transferable实现零拷贝。

Web Worker 的底层原理,其实就三句话能说清:它不是 JavaScript 自己变多线程了,而是浏览器悄悄给你开了个“平行厨房”;主线程和 Worker 不共用锅碗瓢盆(内存不共享),传菜靠“打包快递”(消息机制);想传大件货物不卡顿?得签个“转让协议”(Transferable),把原物直接移交过去。
1. 它不是 JS 多线程,是浏览器给的“独立小房间”
JavaScript 语言本身仍是单线程的——V8 引擎不支持线程共享。但浏览器作为宿主环境,底层是多线程/多进程架构。Web Worker 是浏览器调用系统能力,为你单独启动一个 JS 执行环境:有自己独立的全局对象(self 而非 window)、独立的事件循环、独立的堆内存。它和主线程就像同一栋楼里的两个住户,门牌号不同、水电独立、互不串门。
所以你不能在 Worker 里操作 DOM、访问 document 或 alert——不是语法不让,是根本没这东西。它只配得上 fetch、indexedDB、crypto.subtle、XMLHttpRequest 这类纯计算或 I/O 类 API。
2. 通信靠“快递”,默认是“拍照+寄照片”
主线程和 Worker 之间不能直接读写对方变量,只能通过 postMessage 发消息。这个过程默认使用结构化克隆算法(Structured Clone):
- 它会递归遍历你传的对象,把可序列化的部分(如数组、普通对象、Date、RegExp)深拷贝一份,再塞进另一端的消息队列;
- 不可克隆的(比如函数、undefined、Symbol、DOM 节点)会被静默丢弃;
- 传一个 100MB 的 ArrayBuffer,默认就是复制 100MB 内存——主线程卡一下,Worker 收到的是全新副本,原 buffer 还在主线程里好好的。
3. 大文件不卡,得用“过户式快递”
如果你传的是 ArrayBuffer、TypedArray、ImageBitmap、MessagePort 这些可转移对象,可以加一个 transfer 参数:
- worker.postMessage(arrayBuffer, [arrayBuffer]);
- 这时不是复制,而是把这块内存的“所有权”直接移交给 Worker;
- 移交后,主线程的 arrayBuffer 立刻变成 detached(无法访问、.byteLength 变 0),Worker 拿到的是原始内存地址;
- 这就是“零拷贝”——省掉百兆复制时间,但代价是:你不能再碰原来的 buffer,也不能反复传同一个 buffer。
4. 常驻比临时更省,因为“接电话比装电话快”
很多人一用 Worker 就 new → 计算 → terminate,这在高频场景下反而更慢:
- 每次 new Worker,浏览器要初始化 JS 引擎实例、建立 IPC 通道、加载脚本(哪怕缓存了也要走一遍解析);
- 就像每次打电话都要重新拉光纤、装交换机、拨号;
- 而常驻一个 Worker,相当于装好固定电话,后续只需拨号通话——通信延迟从几百毫秒降到微秒级。


















