前言 見解有限,如有描述不當之處,請幫忙及時指出,如有錯誤,會及時修正。 超長文+多圖預警,需要花費不少時間。 如果看完本文後,還對進程線程傻傻分不清,不清楚瀏覽器多進程、瀏覽器內核多線程、JS單線程、JS運行機制的區別。那麼請回覆我,一定是我寫的還不夠清晰,我來改。。。 __ 正文開始 __ 最近 ...
前言
見解有限,如有描述不當之處,請幫忙及時指出,如有錯誤,會及時修正。
----------超長文+多圖預警,需要花費不少時間。----------
如果看完本文後,還對進程線程傻傻分不清,不清楚瀏覽器多進程、瀏覽器內核多線程、JS單線程、JS運行機制的區別。那麼請回覆我,一定是我寫的還不夠清晰,我來改。。。
----------正文開始----------
最近發現有不少介紹JS單線程運行機制的文章,但是發現很多都僅僅是介紹某一部分的知識,而且各個地方的說法還不統一,容易造成困惑。
因此準備梳理這塊知識點,結合已有的認知,基於網上的大量參考資料,
從瀏覽器多進程到JS單線程,將JS引擎的運行機制系統的梳理一遍。
展現形式:由於是屬於系統梳理型,就沒有由淺入深了,而是從頭到尾的梳理知識體系,
重點是將關鍵節點的知識點串聯起來,而不是僅僅剖析某一部分知識。
內容是:從瀏覽器進程,再到瀏覽器內核運行,再到JS引擎單線程,再到JS事件迴圈機制,從頭到尾系統的梳理一遍,擺脫碎片化,形成一個知識體系
目標是:看完這篇文章後,對瀏覽器多進程,JS單線程,JS事件迴圈機制這些都能有一定理解,
有一個知識體系骨架,而不是似懂非懂的感覺。
另外,本文適合有一定經驗的前端人員,新手請規避,避免受到過多的概念衝擊。可以先存起來,有了一定理解後再看,也可以分成多批次觀看,避免過度疲勞。
大綱
區分進程和線程
瀏覽器是多進程的
瀏覽器都包含哪些進程?
瀏覽器多進程的優勢
重點是瀏覽器內核(渲染進程)
Browser進程和瀏覽器內核(Renderer進程)的通信過程
梳理瀏覽器內核中線程之間的關係
GUI渲染線程與JS引擎線程互斥
JS阻塞頁面載入
WebWorker,JS的多線程?
WebWorker與SharedWorker
簡單梳理下瀏覽器渲染流程
load事件與DOMContentLoaded事件的先後
css載入是否會阻塞dom樹渲染?
普通圖層和複合圖層
從Event Loop談JS的運行機制
事件迴圈機制進一步補充
單獨說說定時器
setTimeout而不是setInterval
事件迴圈進階:macrotask與microtask
寫在最後的話
區分進程和線程
線程和進程區分不清,是很多新手都會犯的錯誤,沒有關係。這很正常。先看看下麵這個形象的比喻:
- 進程是一個工廠,工廠有它的獨立資源
- 工廠之間相互獨立
- 線程是工廠中的工人,多個工人協作完成任務
- 工廠內有一個或多個工人
- 工人之間共用空間
再完善完善概念:
- 工廠的資源 -> 系統分配的記憶體(獨立的一塊記憶體)
- 工廠之間的相互獨立 -> 進程之間相互獨立
- 多個工人協作完成任務 -> 多個線程在進程中協作完成任務
- 工廠內有一個或多個工人 -> 一個進程由一個或多個線程組成
- 工人之間共用空間 -> 同一進程下的各個線程之間共用程式的記憶體空間(包括代碼段、數據集、堆等)
然後再鞏固下:
如果是windows電腦中,可以打開任務管理器,可以看到有一個後臺進程列表。對,那裡就是查看進程的地方,而且可以看到每個進程的記憶體資源信息以及cpu占有率。
所以,應該更容易理解了:進程是cpu資源分配的最小單位(系統會給它分配記憶體)
最後,再用較為官方的術語描述一遍:
進程是cpu資源分配的最小單位(是能擁有資源和獨立運行的最小單位)
線程是cpu調度的最小單位(線程是建立在進程的基礎上的一次程式運行單位,一個進程中可以有多個線程)
tips
不同進程之間也可以通信,不過代價較大
現在,一般通用的叫法:單線程與多線程,都是指在一個進程內的單和多。(所以核心還是得屬於一個進程才行)
瀏覽器是多進程的
理解了進程與線程了區別後,接下來對瀏覽器進行一定程度上的認識:(先看下簡化理解)
瀏覽器是多進程的
瀏覽器之所以能夠運行,是因為系統給它的進程分配了資源(cpu、記憶體)
簡單點理解,每打開一個Tab頁,就相當於創建了一個獨立的瀏覽器進程。
關於以上幾點的驗證,請再第一張圖:
圖中打開了Chrome
瀏覽器的多個標簽頁,然後可以在Chrome的任務管理器
中看到有多個進程(分別是每一個Tab頁面有一個獨立的進程,以及一個主進程)。
感興趣的可以自行嘗試下,如果再多打開一個Tab頁,進程正常會+1以上
註意:在這裡瀏覽器應該也有自己的優化機制,有時候打開多個tab頁後,可以在Chrome任務管理器中看到,有些進程被合併了
(所以每一個Tab標簽對應一個進程並不一定是絕對的)
瀏覽器都包含哪些進程?
知道了瀏覽器是多進程後,再來看看它到底包含哪些進程:(為了簡化理解,僅列舉主要進程)
Browser進程:瀏覽器的主進程(負責協調、主控),只有一個。作用有
負責瀏覽器界面顯示,與用戶交互。如前進,後退等
負責各個頁面的管理,創建和銷毀其他進程
將Renderer進程得到的記憶體中的Bitmap,繪製到用戶界面上
網路資源的管理,下載等
第三方插件進程:每種類型的插件對應一個進程,僅當使用該插件時才創建
GPU進程:最多一個,用於3D繪製等
瀏覽器渲染進程(瀏覽器內核)(Renderer進程,內部是多線程的):預設每個Tab頁面一個進程,互不影響。主要作用為
- 頁面渲染,腳本執行,事件處理等
強化記憶:在瀏覽器中打開一個網頁相當於新起了一個進程(進程內有自己的多線程)
當然,瀏覽器有時會將多個進程合併(譬如打開多個空白標簽頁後,會發現多個空白標簽頁被合併成了一個進程),如圖
另外,可以通過Chrome的更多工具 -> 任務管理器
自行驗證
瀏覽器多進程的優勢
相比於單進程瀏覽器,多進程有如下優點:
避免單個page crash影響整個瀏覽器
避免第三方插件crash影響整個瀏覽器
多進程充分利用多核優勢
方便使用沙盒模型隔離插件等進程,提高瀏覽器穩定性
簡單點理解:如果瀏覽器是單進程,那麼某個Tab頁崩潰了,就影響了整個瀏覽器,體驗有多差;同理如果是單進程,插件崩潰了也會影響整個瀏覽器;而且多進程還有其它的諸多優勢。。。
當然,記憶體等資源消耗也會更大,有點空間換時間的意思。
重點是瀏覽器內核(渲染進程)
重點來了,我們可以看到,上面提到了這麼多的進程,那麼,對於普通的前端操作來說,最終要的是什麼呢?答案是渲染進程
可以這樣理解,頁面的渲染,JS的執行,事件的迴圈,都在這個進程內進行。接下來重點分析這個進程
請牢記,瀏覽器的渲染進程是多線程的(這點如果不理解,請回頭看進程和線程的區分)
終於到了線程這個概念了