前陣子在研究Web Audio API時,發現檔案一多,在解碼和資料的處理就會很慢,查了一下原因主要是因為javascript的單執行緒造成的,所以找到了Web Workers這個東西,可以用來開多執行緒,分擔一些工作;不過研究到最後,並沒有應用到我想解決的問題上,因為Web Workers天生有一些限制在。

Web Workers主要是用來解決比較複雜的運算問題,所以它限制不能做DOM的操作,同時,或是像Web Audio API這種不完全在主執行緒工作的應用也是不能放進Workers的,Web Audio API的多執行緒後來由Google提出的Worklet來處理;那麼Workers到底具體來說可以做什麼事呢 ,我嘗試做了一個實驗,就是在檔案上傳時,先不真的傳到資料庫,而是把檔案先編碼成base64的長字串格式放在Src中,藉此來直接前端啟用播放音樂的功能,這中間最花時間的就是檔案編碼的工作了,所以我把這個工作交給Workers去處理,並比較效益。

就最原始的寫法來說,直接在前端接收使用者選擇的檔案後,new一個fileReader出來,接下來讀檔,編碼再寫回網頁,因為是用迴圈逐一執行的,雖然fileReader.onload是非同步進行的,但是進行編碼時是會佔住主執行緒的資源的,因此其它的檔案就只能等主執行緒空出時間來才能進行,以一次讀進一整張專輯十二首歌來算,平均要花1.66秒才能完成全部的讀檔及編碼的工作。

改成用Workers後,第一個實驗是在主執行緒原本的迴圈中直接開Worker出來,然後把檔案丟進worker去處理,等於是同時開了十二個Workers,這樣跑下來,平均時間縮短到0.86秒,每個worker平均只花33亳秒就完成讀檔及編碼的工作,最花時間的地方是在主執行緒收到Worker回傳的資料後要寫入網頁時,因為這時候主執行緒會依照收到的資料逐一寫入網頁,寫完一筆資料,再寫下一筆,所以卡住了。

最後再做修改,把選擇的檔案清單直接交給一個主要的Worker,由這個Worker去決定要開多少個Worker來讀出檔案及編碼,最後所有資料都回傳給主Worker後,再一次性的回傳給主執行緒來處理,這樣做的話,平均時間縮短到0.24秒,執行緒的總工作時間大概是0.19秒,也就是說,如果主執行緒不要去管多個工作的排程問題的話,單純收到資料並寫入網頁,其實可以很快,而Worker就是在分擔主執行緒的工作這方面發揮了很大的作用。

除了這個簡單的小實驗,另外一個可以嘗試的方式是結合Canvas來使用,動畫或遊戲經常需要大量的計算,可以透過Workers來分擔計算的工作,主執行緒只需要專注最後畫面的呈現就可以了,關於Canvas的應用,我打算過陣子有空找個題目來實作,到時除了Web Workers的應用,還會結合offScreenCanvas這個實驗中的API來試試。

最後修改日期: 2019-06-03

留言

撰寫回覆或留言

發佈留言必須填寫的電子郵件地址不會公開。