0Pricing
JavaScript Academy · 课时

可转移对象

无需复制即可高效移动数据。

可转移对象 是 CoddyKit 上的免费 JavaScript Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 JavaScript Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 JavaScript Academy 课程共包含 4 节课。

克隆的开销

结构化克隆会逐字节复制数据。对于大型 buffer(图像、音频、大型数组),这种复制速度较慢,并且会使内存使用量翻倍。可转移对象通过转移所有权而不是复制来解决这一问题。

可转移的内容

只有特定类型的对象可以转移,其中最重要的是 ArrayBuffer。其他类型还包括 MessagePort、ImageBitmap 和 OffscreenCanvas。

  • ArrayBuffer — 原始二进制内存
  • MessagePort — 通道端点
  • ImageBitmap — 已解码的图像数据

传输列表

postMessage 接受第二个参数:一个可转移对象列表。列表中的对象会被转移,而不是复制。

const buffer = new ArrayBuffer(1024 * 1024); // 1 MB
worker.postMessage(buffer, [buffer]); // transfer it

所有权转移

转移后,发送方将无法再使用该 buffer;它会变为分离状态(byteLength 为 0)。接收方现在拥有同一块底层内存,整个过程不会产生复制。

const buffer = new ArrayBuffer(8);
worker.postMessage(buffer, [buffer]);
console.log(buffer.byteLength); // 0 - now detached

传输类型化数组

您可以通过类型化数组的 .buffer 属性来传输其底层 ArrayBuffer。view 本身不可转移,但它的 buffer 可以转移。

const data = new Float64Array(100000);
worker.postMessage(data, [data.buffer]);
// data is now detached on this side.

接收传输的数据

接收方从 event.data 中读取传输的对象,就像读取经过克隆的消息一样。区别仅在于传输过程中没有发生复制。

// worker.js
self.onmessage = (e) => {
  const buffer = e.data; // we now own this memory
  const view = new Uint8Array(buffer);
  view[0] = 255;
};

传回结果

处理完成后,worker 可以再次传输 buffer,以零拷贝方式将所有权交还给主线程。

// worker.js
self.onmessage = (e) => {
  const buffer = e.data;
  // ...process the bytes...
  self.postMessage(buffer, [buffer]); // transfer back
};

传输与克隆的性能对比

对于几 KB 的数据,两者的差异可以忽略不计。对于数 MB 的二进制数据,传输速度会快得多,还能避免内存峰值。处理大型 buffer 时应优先考虑传输。

避免传输后使用错误

一个常见错误是在传输 buffer 后仍然读取它。一旦 buffer 出现在传输列表中,请始终将其视为已经不可用。

worker.postMessage(buffer, [buffer]);
// BUG: buffer is detached here; this reads zero length.
// const len = buffer.byteLength; // 0

组合克隆数据和传输数据

您可以发送一个包含 buffer 的对象,并且只传输该 buffer。对象会被克隆;列出的 buffer 会被转移。

const msg = { type: 'frame', pixels: buffer };
worker.postMessage(msg, [buffer]);
// msg.type is cloned; buffer is transferred.

何时使用传输

对于图像、音频和视频处理、大型数值计算,以及在线程之间传递大型二进制数据的任何流水线,请使用可转移对象。对于小型、类似 JavaScript 对象表示法的数据,直接克隆更简单,也已经足够。

快速检查

请测试您对可转移对象的理解。

回顾

您已经学会了可转移对象:

  • 将传输列表作为 postMessage 的第二个参数传入。
  • ArrayBuffer(以及少数其他对象)会被转移,而不是复制。
  • 发送方的 buffer 在传输后会变为分离状态。
  • 通过类型化数组的 .buffer 传输它。
  • 大型二进制数据应使用传输,小型数据则使用克隆。

接下来将学习 worker 的应用场景和限制。

常见问题解答

「可转移对象」课时是免费的吗?

是的 — 「可转移对象」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 JavaScript Academy 课程的其余内容,请升级到 CoddyKit PRO。 JavaScript Academy 课程共包含 4 节课。

「可转移对象」这节课中我会学到什么?

无需复制即可高效移动数据。 你通过在浏览器中直接运行的动手代码来练习 JavaScript Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 JavaScript Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 JavaScript Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「可转移对象」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 JavaScript Academy 课中编写并运行代码吗?

能。每节 JavaScript Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 创建 Web Worker
  2. 使用 postMessage 进行消息传递
  3. 可转移对象
  4. 应用场景与限制
← 返回 JavaScript Academy