Web Worker 中使用 Transferable Objects 可实现零拷贝传输,仅移交 ArrayBuffer 等可转移对象的控制权,避免大内存复制;需显式传入 transferList,且移交后原 ArrayBuffer 失效。

Web Worker 中用 Transferable Objects 提升性能,核心就一条:把大块内存(比如图像数据、音频缓冲、计算数组)的控制权直接移交过去,不复制内容。这能省掉几毫秒到几百毫秒的拷贝时间,尤其在传几 MB 甚至上百 MB 数据时效果明显。
哪些对象支持零拷贝传输
不是所有对象都能 transfer,只有明确被浏览器标记为“可转移”的才行:
-
ArrayBuffer:最常用,几乎所有二进制数据底层都靠它,必须传它的实例(比如
typedArray.buffer),不能传 TypedArray 本身 - MessagePort:用于 Worker 之间或主线程与 Worker 之间的通道通信
- ImageBitmap:解码后的图像,适合做离屏处理
- OffscreenCanvas:可在 Worker 里直接绘图,配合 canvas 渲染场景
- AudioData(Chrome 111+):Web Audio 新增的可转移音频帧
⚠️ 注意:TypedArray(如 Uint8Array、Float32Array)本身不可 transfer;你得取它的 .buffer 属性,并确保这个 buffer 是 ArrayBuffer 类型且未被共享。
正确写法:transferList 必须显式声明
光把 ArrayBuffer 当作参数传进去还不够,必须把它放进 postMessage() 的第二个参数——transferList 数组里,否则还是深拷贝。
立即学习“Java免费学习笔记(深入)”;
主线程示例:
const buffer = new ArrayBuffer(10 * 1024 * 1024); // 10MB
const view = new Uint8Array(buffer);
view.fill(1);
<p>// ✅ 正确:buffer 在 transferList 里,真正零拷贝
worker.postMessage({ data: buffer }, [buffer]);</p><p>// ❌ 错误:没写进 transferList → 整个 buffer 被序列化复制
// worker.postMessage({ data: buffer }, []);</p><p>// ❌ 错误:重复 transfer 同一个 buffer → 报 "InvalidStateError"
// worker.postMessage({ data: buffer }, [buffer]);
// worker.postMessage({ data: buffer }, [buffer]);
Worker 内接收和使用要小心失效问题
transfer 成功后,主线程里的那个 ArrayBuffer 就立刻“废了”:.byteLength 变成 0,所有基于它的视图(如 Uint8Array)会报错或读不到数据。
所以在 Worker 里拿到数据后,要立即构建新视图:
self.onmessage = function(e) {
const { data } = e.data; // 这就是移交过来的 ArrayBuffer
const view = new Uint8Array(data); // ✅ 安全,可直接操作
console.log(view.length); // 输出 10485760(10MB)
};
如果主线程后续还要用原数据,就得提前克隆或保留一份副本——transfer 是单向所有权移交,不可逆。
实际提效对比很直观
比如处理一张 4K 图像的像素数据(约 32MB):
- 不 transfer:主线程序列化 + 复制 → 通常耗时 50–200ms,页面明显卡顿
- 用 transfer:只传指针 → 耗时压到
再比如上传前算文件 SHA-256,用 transfer 传 ArrayBuffer 给 Worker,2GB 文件也能边读边算,主线程照常响应滚动和按钮点击。



















