Web Worker 通过 postMessage 传递复杂对象需关注可序列化性、零拷贝需求及浏览器机制;支持结构化克隆的类型包括普通对象、数组、Map、Set、Date、RegExp、ArrayBuffer、TypedArray 等,但函数、DOM 节点、undefined、Symbol、循环引用对象不可传;大数据应使用 transfer list 零拷贝,如 ArrayBuffer;Node.js 的 worker-threads 默认用 BSON 序列化,支持更多类型。

哪些复杂对象能直接传?
以下类型支持结构化克隆(structured clone),可直接 `postMessage(obj)`,无需手动 JSON 序列化:
- 普通对象、数组(含嵌套)、Map、Set(部分浏览器需转为数组再传)
- Date、RegExp、Error(注意:Error 实例在部分环境会被静默丢弃)
- ArrayBuffer、TypedArray(Uint8Array、Float32Array 等)——但强烈建议走 transfer list 零拷贝
- BigInt、Boolean、Number、String、null
⚠️ 这些不能传:函数、DOM 节点、undefined、Symbol、循环引用对象、window/document 实例。传了不会报错,但接收方收不到 event.data,onmessage 根本不触发。
怎么传得更高效?避开深克隆开销
即使对象可克隆,深层嵌套或字段冗余仍会拖慢序列化/反序列化。实际中应主动精简:
- 只提取必要字段:
worker.postMessage({ id, name, timestamp }),别传整个用户对象 - Map/Set 转成二维数组:
Array.from(map.entries())或[...map] - 避免传
undefined字段——结构化克隆会丢掉它,导致接收端属性缺失 - 超过 1MB 的纯 JSON 结构,可先用
msgpack或CBOR压缩,再以ArrayBuffer形式 transfer
大数据必须用 transfer list 零拷贝
对图像像素、音频缓冲、大矩阵等二进制数据,postMessage(data) 是复制,内存翻倍 + CPU 卡顿;正确做法是转移所有权:
立即学习“前端免费学习笔记(深入)”;
- 主线程创建
ArrayBuffer后,必须显式写 transfer list:worker.postMessage({ buffer }, [buffer]) - 传输后,原
buffer.byteLength立即变为 0 —— 这是转移成功的信号 - Worker 内直接拿到原始 buffer,可立即用
new Uint8Array(buffer)操作,无反序列化成本 - 处理完要回传,同样用
self.postMessage({ result }, [resultBuffer])
✅ 支持 transfer 的对象包括:ArrayBuffer、MessagePort、ImageBitmap、OffscreenCanvas。
特殊场景:Node.js 环境下的 worker-threads
如果你用的是 node-webworker-threads(非浏览器),它的 postMessage 底层默认走 BSON 序列化,支持更多原生类型:
-
new Date()、new Buffer()、Map/Set可原样传输 -
thread.emitSerialized(event, data)和worker.postMessage(data)实际调用同一 C++ 方法processEmitSerialized - 但注意:
thread.emit(event, data)会把所有参数.toString()成字符串,丢失类型信息 —— 别误用


















