postMessage是主线程与Worker间唯一安全的异步单向通信机制,本质为结构化克隆+事件驱动:数据不共享、无引用、完全隔离;支持字符串、对象、ArrayBuffer等可克隆类型,禁传函数/DOM节点;须双向预设onmessage监听,大数组可用transferList零拷贝优化。

主线程与 Worker 之间通过 postMessage 实现异步、单向、隔离的消息传递,本质是结构化克隆 + 事件驱动,不共享内存,也不直接访问彼此作用域。
数据传递靠克隆,不是引用
每次调用 postMessage(data),浏览器都会对 data 执行结构化克隆算法,生成一份独立副本:
- 主线程修改原对象,Worker 收到的数据完全不受影响
- Worker 修改接收到的对象,主线程原始数据也不会变化
- 双方操作完全隔离,不存在“响应式同步”或状态联动
- 例如主线程发送
{ count: 1 },Worker 改为{ count: 2 },主线程里的对象仍是{ count: 1 }
支持哪些数据类型
结构化克隆明确支持以下类型,可安全传输:
- 基本类型:字符串、数字、布尔值、
null - 复合对象:普通对象、数组、
Date、RegExp、Map、Set - 二进制数据:
ArrayBuffer、TypedArray、DataView、Blob、File、ImageData
以下类型**不可传**,会报错或被静默忽略:
- 函数、DOM 节点(如
document.body)、undefined、Symbol - 循环引用对象、
Error实例、window或document引用
通信必须双向主动监听
消息不会自动“到达”,双方都需显式绑定监听器:
- 主线程创建 Worker 后,要先设
worker.onmessage或worker.addEventListener('message', ...),再调用worker.postMessage() - Worker 内部必须写
self.onmessage或self.addEventListener('message', ...),才能接收主线程发来的消息 - 推荐用
addEventListener,避免多次赋值onmessage导致监听器被覆盖 - 消息体建议带
type字段,比如{ type: 'process', data: [...] },便于后续扩展多种任务
大数组传输可用零拷贝优化
传大量二进制数据(如图像缓冲区)时,结构化克隆会完整复制 ArrayBuffer,带来性能开销。此时可用 transferList 移交所有权:
- 主线程发送:
worker.postMessage(buffer, [buffer]) - 发送后,主线程的
buffer变为 detached 状态,不可再访问 - Worker 收到的是同一块内存地址,无拷贝开销
- 仅适用于
ArrayBuffer、MessagePort等可转移对象 - 注意:这是单向移交,不是共享内存,仍需靠消息协议协调读写时机

















