SharedWorker 中多个 port 通信时数据结构损坏,本质是 structured clone 算法限制所致:Date、RegExp、Map、Set、class 实例、undefined 等不可序列化类型会被静默丢弃或转为空对象;应统一转为 POJO,发送前用 JSON.stringify/parse 验证,并在收发端做类型校验。

Shared Worker 中多个 port 通信时出现数据类型结构损坏,本质不是“传输过程变形”,而是**序列化/反序列化机制限制 + 消息内容误用**导致的表象异常。浏览器底层通过 structured clone algorithm 复制消息体,它明确不支持函数、undefined、Symbol、RegExp、Date 对象(部分浏览器会转为 {})、Map/Set、Error 实例、DOM 节点等——这些一旦传入 postMessage(),要么被静默丢弃字段,要么整个值变成空对象或 null。
哪些数据结构传过去会“变样”?
以下常见写法会导致接收端拿到意料之外的值:
-
Date 对象:Chrome/Firefox 会转成 {},Safari 可能报错或转为字符串;应统一转为
date.toISOString()或时间戳数字 -
RegExp 实例:一律变为 {};需传
{ source: '...', flags: 'gim' },接收端再new RegExp() -
Map / Set:无法直接传递;应转为数组格式,例如
[...myMap.entries()]或Array.from(mySet) -
class 实例(如 new User()):只保留可枚举属性,原型方法、私有字段、getter/setter 全丢失;应只传 plain object,必要时加
__type: 'User'标识用于重建 -
undefined 字段:在对象中会被 structured clone 完全忽略;若需表达“未定义”,改用
null或显式字段如isUndefined: true
如何安全地收发结构化数据?
核心原则:只传可序列化的纯数据(POJO),所有“行为”和“类型语义”由双方约定协议处理:
- 发送前做一次
JSON.stringify()+JSON.parse()验证:能过就说明结构安全;过不了就说明含非法类型 - 对复杂对象设计扁平化 schema,避免深层嵌套或混合类型数组(如
[1, 'a', {x:2}]) - 关键字段加类型校验:Worker 收到消息后先检查
typeof msg.id === 'string'、Array.isArray(msg.items),不满足则丢弃并 warn - 需要传递二进制数据(如 ArrayBuffer、TypedArray)是允许的,但注意不能是 DataView 或 Blob(Blob 需先读取为 ArrayBuffer)
调试技巧:快速定位结构损坏源头
不要依赖 console.log(e.data) 直接看——它可能隐藏了已损坏的细节:
- 在 Worker 和页面两端都加
console.log('RAW:', JSON.stringify(e.data, null, 2)),对比原始 JSON 字符串是否一致 - 使用
Object.prototype.toString.call(value)检查接收端实际类型,比如[object Object]还是[object Date] - 若发现某字段始终为空,检查发送方是否用了
delete obj.field或赋值为undefined——这两者在 structured clone 中效果不同(前者删除,后者被忽略)

















