可轉移物件

可轉移物件是擁有其資源可以從一個上下文轉移到另一個上下文的物件,從而確保資源在同一時間只有一個上下文可用。轉移後,原始物件將不再可用;它不再指向被轉移的資源,任何嘗試讀取或寫入該物件的操作都會丟擲異常。

可轉移物件通常用於共享一次只能安全地暴露給單個 JavaScript 執行緒的資源。例如,ArrayBuffer 是一個可轉移物件,它擁有一個記憶體塊。當此類緩衝區線上程之間轉移時,關聯的記憶體資源會從原始緩衝區中分離,並附加到新執行緒中建立的緩衝區物件上。原始執行緒中的緩衝區物件將不再可用,因為它不再擁有記憶體資源。

在使用 structuredClone() 建立物件的深複製時,也可以使用轉移。克隆操作完成後,轉移的資源會被移動到克隆物件,而不是被複制。

對於 postMessage()structuredClone(),被轉移的資源必須附加到資料物件上,否則它們在接收端將不可用,因為可轉移陣列僅指示如何傳送某些資源,但實際上並未傳送它們(儘管它們總是會被分離)。

用於轉移物件資源(或其底層資料)的機制取決於具體物件。例如,當 ArrayBuffer 線上程之間轉移時,它指向的記憶體資源在上下文之間被字面地移動,這是一個快速高效的零複製操作。其他物件可能透過複製關聯的資源然後從舊上下文中刪除它來進行轉移。

並非所有物件都是可轉移的。下面提供了可轉移物件列表

線上程之間轉移物件

下面的程式碼演示了當從主執行緒向 Web Worker 執行緒傳送訊息時,轉移是如何工作的。Uint8Array 在 Worker 中被複制(複製),而它的緩衝區被轉移。轉移後,主執行緒中對 uInt8Array 的任何讀寫嘗試都將丟擲異常,但您仍然可以檢查 byteLength 以確認它現在為零。

js
// Create an 8MB "file" and fill it. 8MB = 1024 * 1024 * 8 B
const uInt8Array = new Uint8Array(1024 * 1024 * 8).map((v, i) => i);
console.log(uInt8Array.byteLength); // 8388608

// Transfer the underlying buffer to a worker
worker.postMessage(uInt8Array, [uInt8Array.buffer]);
console.log(uInt8Array.byteLength); // 0

注意:型別化陣列,如 Int32ArrayUint8Array,是可序列化的,但不是可轉移的。然而,它們底層的緩衝區是一個 ArrayBuffer,這是一個可轉移的物件。我們可以將 uInt8Array.buffer 傳送到 data 引數中,但不能將 uInt8Array 傳送到 transfer 陣列中。

在克隆操作期間進行轉移

下面的程式碼展示了一個 structuredClone() 操作,其中底層緩衝區從原始物件複製到克隆物件。

js
const original = new Uint8Array(1024);
const clone = structuredClone(original);
console.log(original.byteLength); // 1024
console.log(clone.byteLength); // 1024

original[0] = 1;
console.log(clone[0]); // 0

// Transferring the Uint8Array would throw an exception as it is not a transferable object
// const transferred = structuredClone(original, {transfer: [original]});

// We can transfer Uint8Array.buffer.
const transferred = structuredClone(original, { transfer: [original.buffer] });
console.log(transferred.byteLength); // 1024
console.log(transferred[0]); // 1

// After transferring Uint8Array.buffer cannot be used.
console.log(original.byteLength); // 0

支援的物件

可以被轉移的介面應在其介紹中包含此資訊。

以下列出了一些不同規範中指示可以轉移的專案(此列表可能不完整!)

注意:可轉移物件在 Web IDL 檔案中使用 [Transferable] 屬性進行標記。瀏覽器支援可能在其各自物件的相容性資訊中透過 transferable 子功能(例如,請參閱 RTCDataChannel)來指示。

另見