我把 Canvas 放 WebWorker 中繪制,性能提升 200%!
最近項目中需要繪制一塊畫布,大致上樣子如下,就是繪制一堆人名在 Canvas 上(實際業務比這個復雜):
大致代碼如下:
頁面肯定不止只有 Canvas 的邏輯,就比如我在繪制畫布后,想去計算 1-100 的數字總和:
但是最終發現,繪制畫布耗費了很多時間,差不多有 1s 的時間,并且堵塞了主進程的代碼,導致了我后續的邏輯被堵住了,下圖可以看到,我的 computedTotal 結果是在畫布繪制完菜執行完的:
所以繪制畫布的耗時過長,阻塞了后續的同步代碼邏輯,這是不合理的,我們需要做優化。
Web Worker?(離屏 Canvas)
我們平時在遇到這類情況的時候,十有八九第一時間都會想到 Web Worker。
但是問題來了:正常來說,Web Worker 中可獲取不了 DOM,做不了畫布繪制呀。
估計會有人想:那我們可以把 Canvas 的 DOM 節點傳入 Web Worker 中嗎?
可以試試!
我們先準備一個 worker.js 來存放 Web Worker 的代碼:
接著在 index.js 中把 Canvas 的 DOM 節點傳過去:
發現會報錯,因為 postMessage 傳數據的時候會進行深拷貝,而 DOM 節點無法被深拷貝:
那么傳上下文過去可以嗎?也可以試試:
可以發現,還是不行:
canvas.transferControlToOffscreen
不得不說 JavaScript 是真的強大,早就為我們準備好了一個 API ,那就是 transferControlToOffscreen:
有了這個 API ,我們就可以把 Canvas 的 DOM 節點以另一種方式傳入 Web Worker 了!!!我們也能在 Web Worker 中去進行 Canvas 的繪制,進而優化主線程的代碼執行效率!!
首先改造一下 drawSunshine,現在只需要傳入 Canvas DOM,不需要在主線程去做繪制:
接著我們在 worker.js 中去接收 DOM 節點,并進行畫布繪制:
最終可以看到,Canvas 的繪制并不會阻塞后續邏輯的執行: