當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


Node.js MessagePort port.postMessage(value[, transferList])用法及代碼示例


port.postMessage(value[, transferList])

曆史
版本變化
v15.6.0

X509Certificate 添加到可克隆類型列表中。

v15.0.0

CryptoKey 添加到可克隆類型列表中。

v15.14.0、v14.18.0

將'BlockList' 添加到可克隆類型列表中。

v15.9.0、v14.18.0

將 'Histogram' 類型添加到可克隆類型列表中。

v14.5.0、v12.19.0

KeyObject 添加到可克隆類型列表中。

v14.5.0、v12.19.0

FileHandle 添加到可轉移類型列表中。

v10.5.0

添加於:v10.5.0


參數

將 JavaScript 值發送到此通道的接收端。 value 以與 HTML structured clone algorithm 兼容的方式傳輸。

特別是,與JSON 的顯著差異是:

const { MessageChannel } = require('node:worker_threads');
const { port1, port2 } = new MessageChannel();

port1.on('message', (message) => console.log(message));

const circularData = {};
circularData.foo = circularData;
// Prints: { foo: [Circular] }
port2.postMessage(circularData);

transferList 可能是 ArrayBuffer MessagePort FileHandle 對象的列表。傳輸後,它們在通道的發送端不再可用(即使它們不包含在 value 中)。與 child processes 不同,目前不支持傳輸網絡套接字等句柄。

如果 value 包含 SharedArrayBuffer 實例,則可以從任一線程訪問這些實例。它們不能在 transferList 中列出。

value 可能仍包含不在 transferList 中的 ArrayBuffer 實例;在這種情況下,底層內存被複製而不是移動。

const { MessageChannel } = require('node:worker_threads');
const { port1, port2 } = new MessageChannel();

port1.on('message', (message) => console.log(message));

const uint8Array = new Uint8Array([ 1, 2, 3, 4 ]);
// This posts a copy of `uint8Array`:
port2.postMessage(uint8Array);
// This does not copy data, but renders `uint8Array` unusable:
port2.postMessage(uint8Array, [ uint8Array.buffer ]);

// The memory for the `sharedUint8Array` is accessible from both the
// original and the copy received by `.on('message')`:
const sharedUint8Array = new Uint8Array(new SharedArrayBuffer(4));
port2.postMessage(sharedUint8Array);

// This transfers a freshly created message port to the receiver.
// This can be used, for example, to create communication channels between
// multiple `Worker` threads that are children of the same parent thread.
const otherChannel = new MessageChannel();
port2.postMessage({ port: otherChannel.port1 }, [ otherChannel.port1 ]);

消息對象立即克隆,發布後可以修改,沒有副作用。

有關此 API 背後的序列化和反序列化機製的更多信息,請參閱 node:v8 模塊的序列化 API。

傳輸TypedArrays 和緩衝區時的注意事項#

所有 TypedArrayBuffer 實例都是底層 ArrayBuffer 的視圖。也就是說,實際存儲原始數據的是ArrayBuffer,而TypedArrayBuffer 對象提供了一種查看和操作數據的方式。在同一個 ArrayBuffer 實例上創建多個視圖是可能的並且很常見。使用傳輸列表傳輸ArrayBuffer 時必須非常小心,因為這樣做會導致共享相同ArrayBuffer 的所有TypedArrayBuffer 實例變得不可用。

const ab = new ArrayBuffer(10);

const u1 = new Uint8Array(ab);
const u2 = new Uint16Array(ab);

console.log(u2.length);  // prints 5

port.postMessage(u1, [u1.buffer]);

console.log(u2.length);  // prints 0

對於Buffer 實例,具體而言,底層ArrayBuffer 是否可以傳輸或克隆完全取決於實例的創建方式,而這通常無法可靠地確定。

ArrayBuffer 可以用 markAsUntransferable() 標記,以指示它應該始終被克隆並且永遠不會轉移。

根據 Buffer 實例的創建方式,它可能擁有也可能不擁有其底層 ArrayBuffer 。除非已知 Buffer 實例擁有它,否則不得轉移 ArrayBuffer。特別是,對於從內部 Buffer 池創建的 Buffer(例如使用 Buffer.from()Buffer.allocUnsafe() ),無法傳輸它們並且它們總是被克隆,這會發送整個 Buffer 的副本水池。此行為可能會帶來意外的更高內存使用率和可能的安全問題。

有關Buffer 池的更多詳細信息,請參閱 Buffer.allocUnsafe()

使用 Buffer.alloc()Buffer.allocUnsafeSlow() 創建的 Buffer 實例的 ArrayBuffer 始終可以傳輸,但這樣做會使這些 ArrayBuffer 的所有其他現有視圖不可用。

使用原型、類和訪問器克隆對象時的注意事項#

因為對象克隆使用 HTML structured clone algorithm ,所以不保留不可枚舉的屬性、屬性訪問器和對象原型。特別是, Buffer 對象將在接收端被讀取為普通的 Uint8Array s,並且 JavaScript 類的實例將被克隆為普通的 JavaScript 對象。

const b = Symbol('b');

class Foo {
  #a = 1;
  constructor() {
    this[b] = 2;
    this.c = 3;
  }

  get d() { return 4; }
}

const { port1, port2 } = new MessageChannel();

port1.onmessage = ({ data }) => console.log(data);

port2.postMessage(new Foo());

// Prints: { c: 3 }

此限製擴展到許多內置對象,例如全局 URL 對象:

const { port1, port2 } = new MessageChannel();

port1.onmessage = ({ data }) => console.log(data);

port2.postMessage(new URL('https://example.org'));

// Prints: { }

相關用法


注:本文由純淨天空篩選整理自nodejs.org大神的英文原創作品 port.postMessage(value[, transferList])。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。