使用Transferable对象可零拷贝转移ArrayBuffer所有权至Worker,主线程buffer变为null,须显式传入transferList,Worker端用新TypedArray包装接收,避免深拷贝与detached错误。

用 Transferable 对象实现零拷贝转移超大数组内存给子线程,核心是把 ArrayBuffer 的所有权移交给 Worker,主线程不再持有该缓冲区,从而避免内存复制。这在处理百万级甚至千万级 Float32Array、Uint8Array 等时能显著提升性能和内存效率。
确认目标数组底层是 ArrayBuffer
只有基于 ArrayBuffer 的视图(如 Uint8Array、Float64Array)才能被转移。普通数组([])、TypedArray 的拷贝副本、或未绑定 buffer 的视图都不支持。
- ✅ 正确:创建时显式传入新
ArrayBuffer - ❌ 错误:用
new Uint8Array(1000000)—— 虽然看起来像,但内部 buffer 可被转移;不过更推荐显式构造以明确控制 - ⚠️ 注意:
typedArray.buffer必须是“可转移的”,即未被其他引用长期持有,且不能是SharedArrayBuffer(后者用于共享,不走 transfer)
使用 postMessage + transfer 参数移交所有权
调用 worker.postMessage(data, [transferList]),把 ArrayBuffer 列在 transferList 中。移交后,主线程原数组的 .buffer 变为 null,试图访问会报 TypeError: Cannot perform %ArrayBuffer% constructor on a detached ArrayBuffer。
- 正确写法:
worker.postMessage({arr: myUint8Array}, [myUint8Array.buffer]) - 也可以直接传 buffer:
worker.postMessage(myUint8Array.buffer, [myUint8Array.buffer]),Worker 内再用new Uint8Array(buf)包装 - 一次可转移多个 buffer:
[buf1, buf2, otherArrayBuffer]
Worker 端接收并重建视图
在 Worker 的 onmessage 回调中,从 event.data 拿到 transferred buffer,然后用它构造新的 TypedArray。此时内存地址不变,只是 JS 引用切换了上下文。
- 示例:
self.onmessage = function(e) { const buf = e.data; const arr = new Float32Array(buf); // 零拷贝重建 // 后续计算直接操作 arr,无需复制 }; - 注意:不能用
e.data.buffer—— 因为e.data就是 buffer 本身(若你直接 post buffer),或需解构取e.data.arr.buffer - 移交后无法再在主线程读写该 buffer,这是强制的内存安全机制
常见陷阱与验证方法
零拷贝容易因小疏忽退化为拷贝,可通过内存占用和时间对比验证是否生效。
- ❌ 忘记加 transfer 列表 → 自动深拷贝,大数组卡死或 OOM
- ❌ 主线程在 postMessage 后还访问
arr[0]或arr.length→ 报 detached 错误 - ✅ 验证方式:Chrome DevTools Memory 面板中观察主线程 ArrayBuffer 是否消失;或用
performance.now()测 postMessage 耗时 —— 几 MB 以下应 - ? 提示:Node.js 的
Worker同样支持 transfer,语法一致

















