Chrome 13 推出了使用結構化複製演算法,將 ArrayBuffer
傳送至/從 Web Worker。這讓 postMessage()
API 除了接受字串,也能接受 File
、Blob
、ArrayBuffer
和 JSON 物件等複雜類型。後續版本的 Firefox 也支援結構化複製功能。
速度越快越好
結構化複製功能很棒,但仍是複製作業。將 32 MB ArrayBuffer
傳遞至 worker 的額外負擔可能會耗費數百毫秒。新版瀏覽器的訊息傳遞功能 (稱為「可轉移物件」) 效能大幅提升。
使用可轉移的物件時,系統會將資料從一個情境轉移到另一個情境。這項功能採用零複製技術,可大幅提升將資料傳送至 Worker 的效能。如果您來自 C/C++ 世界,可以將其視為傳值參照。不過,與傳值參照不同,一旦呼叫內容轉移至新內容,呼叫內容的「版本」就無法再使用。舉例來說,當您將 ArrayBuffer
從主要應用程式轉移至 Worker 時,系統會清除原始 ArrayBuffer
,因此無法再使用。其內容會 (確實) 轉移至 worker 上下文。
如要使用可轉移項目,請使用支援可轉移物件的 postMessage()
新版本:
worker.postMessage(arrayBuffer, [transferableList]);
window.postMessage(arrayBuffer, targetOrigin, [transferableList]);
在 worker 案例中,第一個引數是 ArrayBuffer
訊息。第二個引數是應轉移的項目清單。在本例中,您會在可轉移清單中指定 arrayBuffer
。
基準測試示範
為了讓大家瞭解可轉移項目的效能提升情形,我製作了這部影片。
這個示範會使用 postMessage()
將 32MB 的 ArrayBuffer
傳送至 worker,然後再傳回。如果您的瀏覽器不支援可轉移項目,範例會改用結構化複製功能。在不同瀏覽器中平均執行 5 次,以下是我得到的結果:
在 MacBook Pro/10.6.8/2.53 GHz/Intel Core 2 Duo 上,FF 使用結構化複製功能的速度最快。平均來說,將 32MB 的 ArrayBuffer
傳送至 worker 並回傳至主執行緒的時間為 302 毫秒 (RRT - 往返時間)。與可轉移的測試相比,相同的測試耗時 6.6 毫秒。這可說是大幅提升效能!
有了這類速度,就能在 worker 和主要應用程式之間順暢地傳遞大量 WebGL 紋理/網格。
特徵偵測
這項功能的偵測有點複雜。建議您向 worker 傳送小型 ArrayBuffer
。如果緩衝區已轉移而未複製,其 .byteLength
會變成 0:
var ab = new ArrayBuffer(1);
worker.postMessage(ab, [ab]);
if (ab.byteLength) {
alert('Transferables are not supported in your browser!');
} else {
// Transferables are supported.
}
支援:目前支援 Chrome 17 以上版本、Firefox、Opera、Safari 和 IE10 以上版本
更新 (2011-12-13):程式碼片段,用來顯示 webkitPostMessage()
在視窗和 worker 上的簽名不同。更新 (2016-11-03):移除供應商前置字串並更新程式碼片段