瀏覽器內部結構

一、核心線程

瀏覽器是一個多進程多線程的系統,它會有一個主進程進行任務的調度。有一個第三方插件進程,避免插件崩潰時影響頁面內容。然後每個 tab 頁面都是一個單獨的進程,每個 tab 進程中又有以下幾個重要的線程:

  • GUI 渲染線程
  • JS 引擎線程
  • 定時器線程
  • 異步請求線程
  • 事件觸發線程

1.1 GUI 渲染線程

  • 主要負責頁面的渲染,包括解析 HTML,CSS,構建 DOM 樹 -> CSS 規則樹 -> 渲染樹,最後計算元素的位置、渲染,迴流、重繪等
  • 當執行 JS 引擎線程時,GUI 渲染線程會被掛起,當任務隊列空閒時,GUI 線程恢復執行

1.2 JS 引擎線程

  • 該線程主要負責解析、執行 js 腳本

1.3 定時器線程

  • 該線程負責執行定時器任務,如 setTimeout、setInterval(如果放在主線程計時,受限於 js 單線程,計時會不準)
  • 主線程逐行執行代碼到異步任務時,會將定時器任務交給該線程處理。等到計時結束,事件觸發線程會將回調函數加入到任務隊列尾部,等待 JS 引擎線程執行

1.4 異步請求線程

  • 負責執行異步請求,如 ajax、promise、http
  • 主線程逐行執行代碼到異步請求時,會異步任務交給該線程處理。等到異步任務的狀態碼變更時,事件觸發線程會將回調函數加入到任務隊列尾部,等待 JS 引擎線程執行

1.5 事件觸發線程

主要負責將準備好的事件加入到任務隊列,如 setTimeout 回調、ajax 回調

二、事件循環 Event Loop

2.1 宏任務與微任務

先來道題

console.log('開始')
Promise.resolve().then(()=>{
  console.log('Promise1')
  setTimeout(()=>{
    console.log('setTimeout2')
  },0)
})
setTimeout(()=>{
  console.log('setTimeout1')
  Promise.resolve().then(()=>{
    console.log('Promise2')
  })
},0)

先揭曉答案

  1. 開始
  2. Promise1
  3. setTimeout1
  4. Promise2
  5. setTimeout2 

這是視頻講解

JS 中的事件循環

這裏注意以下幾點即可

  • 首先遇到同步任務,壓入執行棧
  • 遇到微任務壓入微任務隊列
  • 遇到宏任務壓入宏任務隊列
  • 所有的同步任務相當於一個宏任務,而一個宏任務執行完成之後,需要把微任務隊列中的全部任務全部執行

三、Node 中的事件循環

先注意一點,不管是瀏覽器中的事件循環還是 node 中的事件循環,都不是 JS 引擎去實現的,而是瀏覽器和 node 自己實現的東西。

所以即使 chrome 和 node 都用了 V8 引擎,可是二者的事件循環卻完全不是一回事,實現的邏輯也是大相徑庭。

node 中的事件循環是在 libuv 中實現的,libuv 是一個聚焦於 I/O 的庫,一個基於事件驅動的跨平臺抽象層,封裝了不同系統底層一些特性,對外提供統一的 API。

 node.js 的運行機制大致如下:

V8 引擎解析 js 代碼

調用 node API

libuv 負責執行 node API,

參考文章:https://www.jianshu.com/p/5f1a8f586019

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章