昨天提到 postMessage 背後使用了 structuredClone 算法將資料 深複製 (deep copy) 後再進行傳遞,雖然這樣保證了資料的完整性(不同線程間無法修改其他線程的資料),但隨之而來的缺點是當資料量非常大的時候,複製再傳遞的過程會耗費更多時間,今天我們打算實際來測試看看耗費的時間是否會對效能有影響呢?
測試的時間間隔為
主線程發送 postMessage => worker 接收到 message => 主線程接收到 message
程式碼大致如下:
const sendMessage = async (data) => {
return new Promise((resolve) => {
worker.postMessage(data);
worker.onmessage = (e) => {
resolve(e.data);
};
});
};
const start = performance.now();
await sendMessage(data);
const end = performance.now();
const time = end - start;
console.log(`傳遞花費時間:`, `${(time)} ms`);
然後產生要拿來傳送的資料,這裡拿處理 3d 渲染時最常使用到的資料型態 ArrayBuffer,產生的檔案大小從 1KB 到 1GB,使用以下的函式創建:
function generateRandomArray(size) {
const t1 = performance.now();
// value 單位是 Bytes (ex. 1KB 的 value = 1024)
const data = new Uint8Array(new ArrayBuffer(value)).map((_, i) => i);
const t2 = performance.now();
console.log(`創建 Array 經過時間:`, `${t2 - t1} ms`);
return data;
}
測試環境:Macbook M2,Chrome 116
測試環境:Macbook M2,Safari 16.4
在我的電腦上跑的時間如上面兩張圖,不知道是不是因為我的 Chrome 開很多分頁的關係,看起來 Chrome 比 Safari 還要更慢。
至於效能上來說如果要符合 RAIL 性能規範 的建議,在 50ms 以內回應使用者的操作,根據以上結果在約略 20 MB 大小以下的矩陣資料傳遞,使用者不會感受到明顯的卡頓,但如果是在硬體不夠強的手機上,能夠處理資料的上限肯定會更少。
這裡提供 Demo,有興趣的話可以試試在不同的裝置上跑分的結果。
最後想分享的這篇文章 - Is postMessage slow? ,作者根據不同的物件分為廣度、深度等層面進行詳細的測試,包含了各個瀏覽器及電腦、手機跑出來的結果,讓我收穫了很多相關知識,建議大家有興趣的話可以閱讀看看。