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