PostMessage
PostMessage 的 Transfer
https://gemini.google.com/app/80718b22f8173673
PostMessage 語法
// Workers or MessagePort
target.postMessage(message, [transferList]);// Window or Iframe
targetWindow.postMessage(message, targetOrigin, [transferList]);無 Transfer
當 PostMessage 不使用 Transfer 時預設會遞迴地遍歷你傳遞的 message 物件做 Deep Copy 建立副本來給接收方,並且 Deep Copy 支援以下類別:
-
string
-
number
-
boolean
-
null
-
undefined
-
bigint
-
Date
-
RegExp
-
Blob
-
File
-
FileList
-
ArrayBuffer
-
TypedArray
-
DataView
-
Map
-
Set
但是不支援複製 Error 物件、Function` 物件、DOM 節點。
其最終結果會是發送方會有一個原始資料,而接收方會有一個一樣的副本,但是這樣做就有可能會面臨到在 Deep Copy 時遇到了大量資料導致會阻塞發送方的執行緒的問題,如果發送方是主執行緒那就有可能會遇到畫面卡頓。
有 Transfer
當使用了 Transfer 參數的時候就可以做到所有權的轉移,可以指定 message 物件中的特定資料不該用複製的而是直接移交所有權,這樣一來此物件的所有權就會交到接收方的執行緒,就不需要建立副本給接收方,但除此之外還有幾點:
-
傳送方會失去所有權,所以傳送方如果調用 Transfer 的物件時會得到 Error。
-
接收方會得到著個物件,且這個物件是直接指向底層的數據緩衝區或資源。
-
因為沒有複製資料,只是指標的移轉,所以非常高效率幾乎不會有延遲
詳細是怎麼運作
以 ArrayBuffer 為例
-
沒有
transfer(複製):-
傳送方
postMessage(buffer)。 -
瀏覽器引擎在接收方的執行緒環境中分配一塊新的、同樣大小的記憶體。
-
引擎將原始記憶體塊的數據逐字節複製到新的記憶體塊。
-
接收方得到一個指向新記憶體塊的
ArrayBuffer物件。 -
傳送方仍然持有指向原始記憶體塊的
ArrayBuffer物件。
-
-
使用
transfer(轉移):-
傳送方
postMessage(buffer, [buffer])。 -
瀏覽器引擎接收到轉移指令。
-
引擎撤銷傳送方
ArrayBuffer物件與其底層原始記憶體塊之間的連結(使其 “neutered”)。 -
引擎在接收方的執行緒環境中建立一個新的
ArrayBuffer物件。引擎將這個新的ArrayBuffer物件指向先前那個原始的記憶體塊。 -
接收方得到一個指向原始記憶體塊的
ArrayBuffer物件。 -
核心:數據本身從未移動或複製,只是控制權/存取權限被轉移了。
-