瀏覽器四大進程


一、瀏覽器四大進程

1.Browser進程:瀏覽器的主進程(負責協調、主控),只有一個。

    主要作用:

  • 負責瀏覽器界面顯示,與用戶交互。如前進,后退等
  • 負責各個頁面的管理,創建和銷毀其他進程
  • 將渲染(Renderer)進程得到的內存中的Bitmap(位圖),繪制到用戶界面上
  • 網絡資源的管理,下載等

2、第三方插件進程:每種類型的插件對應一個進程,僅當使用該插件時才創建
3、GPU進程:最多一個,用於3D繪制等
4、瀏覽器渲染進程(即通常所說的瀏覽器內核)(Renderer進程,內部是多線程的):主要作用為頁面渲染,腳本執行,事件處理等

 

二.瀏覽器多進程的優勢

相比於單進程瀏覽器,多進程有如下優點:

  • 避免單個page crash影響整個瀏覽器
  • 避免第三方插件crash影響整個瀏覽器
  • 多進程充分利用多核優勢
  • 方便使用沙盒模型隔離插件等進程,提高瀏覽器穩定性

簡單點理解:如果瀏覽器是單進程,那么某個Tab頁崩潰了,就影響了整個瀏覽器,體驗有多差;同理如果插件崩潰了也會影響整個瀏覽器;而且多進程還有其它的諸多優勢。當然,多進程,內存等資源消耗也會更大,有點空間換時間的意思。

三.渲染進程包括哪些線程

  1. GUI渲染線程
  • 負責渲染瀏覽器界面,解析HTML,CSS,構建DOM樹和RenderObject樹,布局和繪制等。
  • 當界面需要重繪(Repaint)或由於某種操作引發回流(reflow)時,該線程就會執行
  • 注意,GUI渲染線程與JS引擎線程是互斥的,當JS引擎執行時GUI線程會被掛起(相當於被凍結了),GUI更新會被保存在一個隊列中等到JS引擎空閑時立即被執行。
  1. JS引擎線程(單線程)
  • 也稱為JS內核,負責處理Javascript腳本程序。(例如常常聽到的谷歌瀏覽器的V8引擎,新版火狐的JaegerMonkey引擎等)
  • JS引擎線程負責解析Javascript腳本,運行代碼。
  • JS引擎一直等待着任務隊列中任務的到來,然后加以處理,一個Tab頁(renderer進程)中無論什么時候都只有一個JS線程在運行JS程序
  • 同樣注意,GUI渲染線程與JS引擎線程是互斥的,所以如果JS執行的時間過長,這樣就會造成頁面的渲染不連貫,導致頁面渲染加載阻塞。
  1. 事件觸發線程
  • 歸屬於渲染進程而不是JS引擎,用來控制事件輪詢(可以理解,JS引擎自己都忙不過來,需要瀏覽器另開線程協助)
  • 當JS引擎執行代碼塊如鼠標點擊、AJAX異步請求等,會將對應任務添加到事件觸發線程中
  • 當對應的事件符合觸發條件被觸發時,該線程會把事件添加到待處理任務隊列的隊尾,等待JS引擎的處理
  • 注意,由於JS的單線程關系,所以這些待處理隊列中的事件都得排隊等待JS引擎處理(當JS引擎空閑時才會去執行)
  1. 定時觸發器線程

    • 定時器setInterval與setTimeout所在線程
    • 瀏覽器定時計數器並不是由JavaScript引擎計數的,(因為JavaScript引擎是單線程的, 如果任務隊列處於阻塞線程狀態就會影響記計時的准確)
    • 因此通過單獨線程來計時並觸發定時(計時完畢后,添加到事件隊列中,等待JS引擎空閑后執行)
    • 注意,W3C在HTML標准中規定,規定要求setTimeout中低於4ms的時間間隔算為4ms。
  2. 異步http請求線程

    • 用於處理請求XMLHttpRequest,在連接后是通過瀏覽器新開一個線程請求。如ajax,是瀏覽器新開一個http線程
    • 將檢測到狀態變更(如ajax返回結果)時,如果設置有回調函數,異步線程就產生狀態變更事件,將這個回調再放入js引擎線程的事件隊列中。再由JavaScript引擎執行。


       
      2084336019-5a65972413011.png

知道了這幾個線程,那么通過這幾個線程,js是怎么執行的呢?

三.渲染進程中的線程之間的關系

GUI渲染線程與JS引擎線程互斥

由於JavaScript是可操縱DOM的,如果在修改這些元素屬性同時渲染界面(即JS線程和GUI線程同時運行),那么渲染線程前后獲得的元素數據就可能不一致了。

因此為了防止渲染出現不可預期的結果,瀏覽器設置GUI渲染線程與JS引擎為互斥的關系,當JS引擎執行時GUI線程會被掛起,
GUI更新則會被保存在一個隊列中等到JS引擎線程空閑時立即被執行。

JS阻塞頁面加載

從上述的互斥關系,可以推導出,JS如果執行時間過長就會阻塞頁面。

譬如,假設JS引擎正在進行巨量的計算,所以JS引擎很可能很久很久后才能空閑,所以導致頁面渲染加載阻塞。這就牽扯到script標簽在html中的存放位置。具體可以看我另一篇文章 為什么script標簽一般放在body下面

四.js引擎是單線程的

我們知道js是單線程的。也就是說,同一個時間只能做一件事。那么,為什么JavaScript不能有多個線程呢?這樣能提高效率啊。

參考阮一峰大神的文章js事件輪詢(Event Loop)

  • JavaScript的單線程,與它的用途有關。作為瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操作DOM。這決定了它只能是單線程,否則會帶來很復雜的同步問題。比如,假定JavaScript同時有兩個線程,一個線程在某個DOM節點上添加內容,另一個線程刪除了這個節點,這時瀏覽器應該以哪個線程為准?
  • 所以,為了避免復雜性,從一誕生,JavaScript就是單線程,這已經成了這門語言的核心特征,將來也不會改變。
  • 為了利用多核CPU的計算能力,HTML5提出Web Worker標准,允許JavaScript腳本創建多個線程,但是子線程完全受主線程控制,且不得操作DOM。所以,這個新標准並沒有改變JavaScript單線程的本質。

五.js事件輪詢

上面我們已經知道JS引擎是單線程,任務應該是按順序執行的,那么怎么會有同步異步之說?

  • 單線程就意味着,所有任務需要排隊,前一個任務結束,才會執行后一個任務。如果前一個任務耗時很長,后一個任務就不得不一直等着。
  • 如果排隊是因為計算量大,CPU忙不過來,倒也算了,但是很多時候CPU是閑着的,因為IO設備(輸入輸出設備)很慢(比如Ajax操作從網絡讀取數據),不得不等着結果出來,再往下執行。
  • JavaScript語言的設計者意識到,這時主線程完全可以不管IO設備,掛起處於等待中的任務,先運行排在后面的任務。等到IO設備返回了結果,再回過頭,把掛起的任務繼續執行下去。
  • 於是,所有任務可以分成兩種,一種是同步任務(synchronous),另一種是異步任務(asynchronous)。同步任務指的是,在主線程上排隊執行的任務,只有前一個任務執行完畢,才能執行后一個任務;異步任務指的是,不進入主線程、而進入"任務隊列"(task queue)的任務,只有"任務隊列"通知主線程,某個異步任務可以執行了,該任務才會進入主線程執行。

理解了同步異步。其實其最本質原因就是基於js的事件輪詢機制。

  1. 所有同步任務都在主線程(即js引擎線程)上執行,形成一個執行棧
  2. 而異步任務均由事件觸發線程控制,其有一個任務隊列。只要異步任務有了運行結果,就在"任務隊列"之中放置回調事件。異步任務必須指定回調函數,當主線程開始執行異步任務,就是執行對應的回調函數。所以所謂"回調函數"(callback),就是那些會被主線程掛起來的代碼。
  3. 一旦"執行棧"中的所有同步任務執行完畢,系統就會讀取"任務隊列",按順序結束等待狀態,進入執行棧,開始執行。
  4. 主線程不斷重復上面的第三步
  5. 只要主線程空了,就會去讀取"任務隊列",這個過程會不斷重復。這就是JavaScript的運行機制。又稱為Event Loop(事件循環或者輪詢)。

六.定時器觸發線程

上述事件循環機制的核心是:JS引擎線程和事件觸發線程

js來控制主線程,事件觸發來控制任務隊列就如主線程。

為什么要單獨的定時器線程?因為JavaScript引擎是單線程的, 如果處於阻塞線程狀態就會影響記計時的准確,因此很有必要單獨開一個線程用來計時。

什么時候會用到定時器線程?當使用setTimeout或setInterval時,它需要定時器線程計時,計時完成后就會將特定的事件推入事件觸發線程的任務隊列中。等待進入主線程執行。

譬如:

setTimeout(function(){ console.log('hello!'); }, 1000); 

這段代碼的作用是當1000毫秒計時完畢后(由定時器線程計時),將回調函數推入事件隊列中,等待主線程執行

setTimeout(function(){ console.log('hello!'); }, 0); console.log('begin'); //begin hello 

這段代碼的效果是表示當前代碼執行完(執行棧清空)以后,立即執行(0毫秒間隔)指定的回調函數。

注意:

  • 雖然代碼的本意是0毫秒后就推入事件隊列,但是html5標准中規定,規定要求setTimeout中低於4ms的時間間隔算為4ms。
  • 就算不等待4ms,就算假設0毫秒就推入事件隊列,也會先執行begin(因為只有主線程可執行棧內空了后才會主動讀取事件隊列)。要是當前代碼耗時很長,有可能要等很久,所以並沒有辦法保證,回調函數一定會在setTimeout()指定的時間執行。同理setInterval則是每次都精確的隔一段時間推入一個事件(但是,事件的實際執行時間不一定就准確,還有可能是這個事件還沒執行完畢,下一個事件就來了)

參考:  線程和進程
https://segmentfault.com/a/1190000012925872



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM