瀏覽器核心中各個執行緒之間的關係
到了這裡,已經對瀏覽器的執行有了一個整體的概念,接下來,先簡單梳理一些概念 :
GUI渲染執行緒與JS引擎執行緒互斥
由於JavaScript是可操縱DOM的,如果在修改這些元素屬性同時渲染介面(即JS執行緒和UI執行緒同時執行),那麼渲染執行緒前後獲得的元素資料就可能不一致了。
因此為了防止渲染出現不可預期的結果,瀏覽器設定GUI渲染執行緒與JS引擎為互斥的關係,當JS引擎執行時GUI執行緒會被掛起,
GUI更新則會被儲存在一個佇列中等到JS引擎執行緒空閒時立即被執行。
JS阻塞頁面載入
從上述的互斥關係,可以推匯出,JS如果執行時間過長就會阻塞頁面。
譬如,假設JS引擎正在進行巨量的計算,此時就算GUI有更新,也會被儲存到佇列中,等待JS引擎空閒後執行。
然後,由於巨量計算,所以JS引擎很可能很久很久後才能空閒,自然會感覺到巨卡無比。
所以,要儘量避免JS執行時間過長,這樣就會造成頁面的渲染不連貫,導致頁面渲染載入阻塞的感覺。
WebWorker,JS的多執行緒?
前文中有提到JS引擎是單執行緒的,而且JS執行時間過長會阻塞頁面,那麼JS就真的對cpu密集型計算無能為力麼?
所以,後來HTML5中支援了Web Worker
。
MDN的官方解釋是:
Web Worker為Web內容在後臺執行緒中執行指令碼提供了一種簡單的方法。執行緒可以執行任務而不干擾使用者介面 一個worker是使用一個建構函式建立的一個物件(e.g. Worker()) 執行一個命名的JavaScript檔案 這個檔案包含將在工作執行緒中執行的程式碼; workers 執行在另一個全域性上下文中,不同於當前的window 因此,使用 window快捷方式獲取當前全域性的範圍 (而不是self) 在一個 Worker 內將返回錯誤
這樣理解下:
-
建立Worker時,JS引擎向瀏覽器申請開一個子執行緒(子執行緒是瀏覽器開的,完全受主執行緒控制,而且不能操作DOM)
-
JS引擎執行緒與worker執行緒間通過特定的方式通訊(postMessage API,需要通過序列化物件來與執行緒互動特定的資料)
所以,如果有非常耗時的工作,請單獨開一個Worker執行緒,這樣裡面不管如何翻天覆地都不會影響JS引擎主執行緒,
只待計算出結果後,將結果通訊給主執行緒即可,perfect!
而且注意下,JS引擎是單執行緒的,這一點的本質仍然未改變,Worker可以理解是瀏覽器給JS引擎開的外掛,專門用來解決那些大量計算問題。
其它,關於Worker的詳解就不是本文的範疇了,因此不再贅述。