结构化克隆通过序列化→IPC传输→反序列化三步实现“复制不共享”:发送方转为二进制流,跨线程传输后,接收方重建独立实例,内存与引用完全隔离。

主线程与 Worker 之间通过 postMessage 通信时,浏览器自动启用结构化克隆算法(Structured Clone Algorithm),它不是手动调用的函数,而是底层机制——每次传数据,都会生成一份独立、类型保真、无副作用的副本,双方内存完全隔离。
它怎么做到“复制但不共享”?
整个过程分三步,在不同线程中独立完成:
-
序列化:发送方(如主线程)遍历对象图,识别可克隆类型(Object、Map、Date、ArrayBuffer 等),将其转为平台无关的内部二进制表示;不可克隆项(如函数、DOM 节点、Error)直接报
DataCloneError - 传输:该二进制流经内核级 IPC 通道(如 Chromium 的 Mojo)传递,不经过 JS 引擎,避免阻塞主线程
- 反序列化:接收方(如 Worker)用相同逻辑重建对象——新 Date 实例、新 Map 实例、新 ArrayBuffer 内存块,所有引用关系还原,但与原对象物理地址不同
哪些类型能被正确克隆?
现代浏览器(Chrome 98+、Firefox 94+、Safari 15.4+)支持以下类型,且保持原始语义:
- 基础值:null、boolean、number、string、bigint(部分需开启 flag)
- 复合结构:Object、Array、Date、RegExp、Map、Set、TypedArray、DataView
- 二进制与媒体:ArrayBuffer、Blob、File、ImageData、ImageBitmap
不支持的类型包括:function、Error、Promsie、Proxy、WeakMap、document、window、console,传入会报错或静默丢弃。
为什么它比 JSON 更可靠?
JSON 只是文本协议,天然丢失类型和行为:
- Date 变成字符串,失去
.getTime()方法 - RegExp 变成空对象,正则逻辑彻底消失
- Map/Set 变成普通 Object,键值对关系与迭代顺序全丢
- 循环引用直接崩溃,无法处理
结构化克隆在引擎层直操作 JS 值内部表示,跳过字符串编码/解析,保留原型链、内部属性(如 RegExp 的 flags)、引用关系(Map 中对象 key 仍对应同一逻辑 key),并用映射表安全处理循环引用。
大数组怎么避免拷贝开销?
当传输大量二进制数据(如图像像素、音频缓冲)时,普通克隆会双倍占用内存并消耗 CPU。此时应使用 Transferable Objects:
- 只适用于
ArrayBuffer、MessagePort、ImageBitmap等可转移对象 - 语法:
worker.postMessage(buffer, [buffer]) - 执行后,主线程的
buffer立即 detached(byteLength === 0),Worker 收到的是同一内存块的所有权,零拷贝 - 注意:这不是共享内存,而是单向移交;后续再访问原 buffer 会静默失败

















