postMessage 报错“DataCloneError”是因为结构化克隆算法不支持 Date、RegExp、Map 等类型;structuredClone 可预处理数据以兼容 postMessage,但需注意浏览器支持(Chrome 98+等),旧版需手动序列化降级。

postMessage 报错 “DataCloneError: An object could not be cloned” 怎么回事
当你用 postMessage 传一个含 Date 对象的普通对象(比如 { timestamp: new Date() }),Chrome 或 Firefox 会直接抛出 DataCloneError。这不是 bug,是规范限制:原生 postMessage 的结构化克隆算法(structured clone algorithm)**不支持直接序列化 Date、RegExp、Map、Set 等非可枚举/非纯数据类型**——哪怕它们看起来“只是个时间戳”。
为什么不能直接 JSON.stringify + parse
手动转成字符串再还原看似可行,但会丢失原型链、方法、不可枚举属性,且对嵌套 Date、undefined、BigInt、function(虽然 postMessage 本来也不支持)等处理脆弱。更重要的是:JSON.stringify(new Date()) 返回字符串,再 JSON.parse() 得到的是字符串,不是 Date 实例——你得额外遍历修复,容易漏。
- 无法自动还原
Date、RegExp、ArrayBuffer视图等类型 - 遇到
undefined或function字段时静默丢弃(不报错但数据不全) - 循环引用直接抛
TypeError
structuredClone 是什么,它能直接替代 postMessage 吗
不能。structuredClone 是一个独立的同步深拷贝 API,它使用和 postMessage **同一套结构化克隆算法**(但更完整),支持 Date、RegExp、Map、Set、ArrayBuffer、TypedArray、BigInt 等——只要目标环境支持(Chrome 98+、Firefox 94+、Safari 16.4+)。但它本身不发送消息,只是帮你把数据“准备好”。
正确用法是:先用 structuredClone 拷一份兼容结构化克隆的数据,再传给 postMessage —— 这样既保留类型,又不触发错误。
const data = {
timestamp: new Date(),
meta: new Map([['id', 123]])
};
// ✅ 安全:structuredClone 后再发
window.parent.postMessage(structuredClone(data), '*');
兼容性不足时怎么降级
如果要支持旧浏览器(如 Safari structuredClone。此时必须自己实现轻量级“Date 友好”的克隆逻辑,只处理你实际用到的类型:
- 检测值是否为
Date:用val instanceof Date,转成val.toISOString()字符串 - 接收方收到后,检查字段名(如
timestamp)或值格式(ISO 8601 正则),再 newDate(val) - 避免递归处理整个对象——只对已知含
Date的字段做转换,其余走JSON.parse(JSON.stringify()) - 不要试图 polyfill
structuredClone全功能:它涉及底层内存复制,JS 无法完全模拟
真正麻烦的不是 Date 本身,而是你不知道下游会不会在某个嵌套层级突然塞进一个 RegExp 或 Map —— 所以生产环境若需强兼容,建议明确约束数据 schema,并在发送前用 structuredClone(有就用,没有就报错或拒绝发送)。

















