Transferable对象的核心价值是零拷贝移交内存所有权,而非复制数据;支持对象包括ArrayBuffer、MessagePort、ImageBitmap、OffscreenCanvas和WebAssembly.Memory,须显式传入transferList才能生效。

Transferable Objects 的核心价值,就是把数据“交出去”,而不是“复制一份送过去”。它不走序列化/反序列化流程,直接移交内存所有权,所以快、轻、零拷贝。
哪些对象支持所有权转移
不是所有数据都能转移,只有浏览器明确标记为 可转移(transferable) 的对象才行。常见且实用的包括:
- ArrayBuffer:最常用,承载二进制数据的基础容器
- MessagePort:用于 Worker 间通信或主线程与 Worker 的高级通道
- ImageBitmap:图像解码后的高效位图表示
- OffscreenCanvas:可在 Worker 中直接绘图的画布
- WebAssembly.Memory:Wasm 模块的线性内存实例(Kotlin/Wasm 场景中尤其关键)
普通对象、字符串、数组(Array)、Date、RegExp 等都不在名单里——它们只能走结构化克隆,必然触发拷贝和 GC 压力。
正确写法:必须带 transfer list
光传对象不够,必须显式声明“我要转移它”。这个声明叫 transfer list,是 postMessage() 的第二个参数:
✅ 正确(零拷贝)worker.postMessage(buffer, [buffer]);
❌ 错误(退化为结构化克隆,全量拷贝)worker.postMessage(buffer); // 缺少 transfer list
一旦转移成功,原上下文中的该对象立即失效:console.log(buffer.byteLength); // 输出 0
后续再访问 buffer 或其视图(如 new Uint8Array(buffer))会报错或静默失败。
典型工作流:传入 → 处理 → 传回
所有权可以来回切换,适合分阶段处理大块数据:
- 主线程分配
ArrayBuffer,填入原始数据(如音频采样、图像像素) - 调用
worker.postMessage(buffer, [buffer]),把 buffer 所有权移给 Worker - Worker 内直接创建视图(如
new Float32Array(buffer)),原地计算,不申请新内存 - 处理完后,再次调用
self.postMessage(buffer, [buffer]),把所有权转回主线程 - 主线程收到后,可继续读取或交给 Canvas/WebGL 使用
整个过程没有内存复制,也没有中间序列化开销,实测传输 10MB 数据耗时约 1ms 左右。
避坑要点
几个高频出错点,直接影响是否真能“极速”:
-
别嵌套在普通对象里传:如
postMessage({id: 1, data: buffer}, [buffer])是合法的;但若写成postMessage({id: 1, data: buffer})(漏 transfer list),buffer 就会被克隆,彻底失去零拷贝意义 - 确认目标环境支持:SharedArrayBuffer 需要跨域隔离策略(COOP/COEP),但 ArrayBuffer 转移本身无此限制,兼容性更好
-
Kotlin/Wasm 场景注意封装层:某些 Kotlin/Wasm 运行时会自动包装 ArrayBuffer(如
WasmMemoryBuffer),需确认其.buffer属性是否暴露且可转移,示例中正是直接传data.buffer

















