arraybuffer.transfer()是es2025引入的零拷贝内存转移特性,通过移交所有权而非复制数据实现高效传输,调用后原buffer变为detached状态,目标环境直接获得同一物理内存控制权。

直接转移 ArrayBuffer 所有权,不复制内存,是 Web 线程间超高性能传输的核心手段。关键不在“传数据”,而在“交钥匙”——把底层内存的控制权从主线程移交给 Worker,双方不共享、不拷贝、不等待。
只传 ArrayBuffer,不传视图或普通数组
可转移对象有明确类型限制:只有 ArrayBuffer、MessagePort、ImageBitmap、OffscreenCanvas 等原生对象支持转移。TypedArray(如 Uint8Array)本身不可转移,必须取它的 .buffer 属性:
- ✅ 正确:
const buf = new ArrayBuffer(10 * 1024 * 1024); worker.postMessage({data: buf}, [buf]); - ❌ 错误:
const view = new Uint8Array(buf); worker.postMessage({data: view}, [view]);—— view 不在可转移列表中,会触发结构化克隆,产生完整拷贝 - ⚠️ 注意:用
new Uint8Array(1000000)创建的视图,其.buffer虽可转移,但隐式创建不易追踪,建议显式构造 ArrayBuffer 以确保可控
移交后原引用立即失效,需主动规避访问
调用 postMessage(data, [buffer]) 后,主线程中的 buffer 并未被销毁,但已处于 detached 状态:
-
buffer.byteLength变为0,任何读写操作(如new Uint8Array(buffer))都会抛出TypeError: Cannot perform %ArrayBuffer% constructor on a detached ArrayBuffer - Worker 收到的消息中,
message.data是同一块物理内存的 ArrayBuffer 引用,可直接用于构建新视图:const arr = new Float32Array(message.data); - 若需多次复用,应在移交前完成所有主线程侧处理;移交后勿再保留对 buffer 的引用,避免意外访问
一次转移仅限一次,重复传会报错
同一个 ArrayBuffer 只能被转移一次。常见陷阱包括:
- 误将已转移的 buffer 再次放入 transfer 列表(如两次调用
postMessage(..., [buf])),触发DataCloneError - 多个 Worker 同时需要同一份数据?不能反复转移,应由主线程分别创建独立 ArrayBuffer,或改用
SharedArrayBuffer + Atomics实现真正共享(注意跨域和安全策略限制) - 图像处理中使用
ImageBitmap时,Chrome 支持良好,但 Firefox 和 Safari 需检测createImageBitmap返回对象是否具备transferToImageBitmap方法,否则回退为 canvas 绘制+toBlob
性能差距真实显著,不是理论优化
实测 10MB ArrayBuffer:
- 传统
postMessage({data: buf}):平均耗时 15–25ms(含序列化、内存分配、深拷贝) - Transferable 方式:
postMessage({data: buf}, [buf]):平均耗时仅 0.1–0.5ms - 提速达 50–200 倍,且内存占用减半——主线程释放缓冲区后,GC 可立即回收关联对象,Worker 独占内存无竞争










