每天都在用的瀏覽器,你知道它是如何工作的嗎?

2019-09-06 08:20:12


導語:本文從市面主流的瀏覽器及相應的核心引擎開始,介紹了Chromium為代表的瀏覽器架構及Blink核心的功能架構。Chromium為多程序架構,使用者從啟動執行瀏覽器後,先後經過頁面導航、渲染、資源載入、樣式計算、佈局、繪製、合成到柵格化,最後完成GPU展示。而頁面渲染完成後,瀏覽器如何響應頁面操作事件也進行了深入的介紹。良心推薦!

本文第二至五部分內容根據 Mariko Kosaka 的英文原版《Inside look at modern web browser》(見參考文獻),進行翻譯、理解、總結提煉、條理化、加入應用示例、進行相關知識補充擴充套件而來。

一、瀏覽器概論
瀏覽器經歷了很多年的發展,瀏覽器引擎也在不停地迭代和演進。從PC時代到移動端,以獨立瀏覽器的形態還是以系統WebView元件內嵌的形態存在,在網際網路的生態系統中一直扮演著重要的角色。瞭解瀏覽器及其原理可以讓我們開啟另一個世界。

1. 瀏覽器引擎

以下是市面留存的主流瀏覽器的引擎介紹。

1.1 瀏覽器引擎

  • Trident:IE瀏覽器引擎
  • Gecko:Firefox瀏覽器引擎
  • Presto:Opera瀏覽器引擎
  • Webkit:Safari,Google Chrome瀏覽器引擎。

1) Chromium:基於webkit,08年開始作為Chrome的引擎,Chromium瀏覽器是Chrome的實驗版,實驗新特性。

2) Webkit2:2010年隨OS X Lion一起面世。WebCore層面實現程序隔離與Google的沙箱設計存在衝突。

3) Blink:基於Webkit2分支,13年穀歌開始作為Chrome 28的引擎整合在Chromium瀏覽器裡。Android的WebView同樣基於Webkit2。

1.2 微軟瀏覽器

目前PC場景作業系統仍是windows一統天下,對桌面使用者來說,雖然IE的市場份額在下降,但是IE曾經也風光過。IE核心以Trident為主,最新的Edge也相容了Chromium核心。

Microsoft Edge:核心為:EDGE,Windows 10預設瀏覽器,不能單獨下載安裝。相容Chromium核心,同時保留EDGE核心來相容企業網站

  • Internet Explorer 11:Windows 8.1,引擎Trident 7.0

  • Internet Explorer 10:Windows 8預設瀏覽器,引擎Trident

  • Internet Explorer 9

  • Internet Explorer 8:Windows 7整合

  • Internet Explorer 7:Windows Vista整合,2016年停止支援

  • Internet Explorer 6:2014年停止支援


2. 瀏覽器架構

目前chromium瀏覽器的架構主要由下以幾個部分構成。


以下為架構的介紹:

  • 作業系統:WebKit可以執行在不同的作業系統上,如Chromium瀏覽器支援Windows、Linux、Android等系統;

  • 第三方庫:這些庫是WebKit執行的基礎,包括2D圖形庫、3D圖形庫、網路庫、儲存庫、音視訊庫等;

  • WebCore:WebKit載入和渲染網頁的基礎,是不同瀏覽器所使用的WebKit中共享的部分,包括HTML解析器、CSS解析器、SVG、佈局、渲染樹等等;

  • JavaScript引擎:JavaScript解析器,WebKit預設的引擎是JavaScriptCore,Google的Blink為V8引擎;

  • WebKit Ports:WebKit中的移植部分,包括網路棧、音視訊解碼、硬體加速等模組,這部分對WebKit的功能和效能影響比較大。

  • WebKit嵌入式介面:WebKit對外暴露的介面層,這個介面是提供給瀏覽器呼叫的,如給chromium呼叫,因為介面與具體的移植也有關係,所以中間會有一個WebKit繫結層

JavaScriptCore(用於Safari)

  • JavaSript Parser,JSON Parser
  • 位元組編譯器:使用內部位元組碼格式
  • 彙編程式:在執行時使用程式碼修補 - >它需要可寫程式碼記憶體
  • 資料流圖:基於編譯時推測優化生成程式碼的新舉措
  • 直譯器:執行生成的位元組碼
  • Regexp引擎:支援JIT
  • 垃圾收集器:標記和掃描
  • 執行時:所有JS全域性物件(日期,字串,數字等)
  • 偵錯程式,Profiler

WebCore

  • 資源載入器:HTML和XML解析器,DOM
  • SVG和SMIL
  • CSS:分析器,選擇器,動畫
  • 渲染和佈局
  • 繫結生成器:IDL檔案:JSC,V8,ObjC
  • HTML5:音訊,視訊,畫布,WebGL,通知功能
  • WebInspector
  • 平臺整合:圖形,字型,聲音,視訊

相關資

  • Blink核心:https://src.chromium.org/viewvc


2.1 多程序架構
圖片引自chromium-design-doc

2.1.1 Chromium多程序架構

早期的web瀏覽器頁面行為不當、瀏覽器錯誤、瀏覽器外掛錯誤都會引起整個瀏覽器或當前執行的選項卡關閉。因此將chromium應用程式放在相互隔離的獨立的程序中:

  • 單個程式崩潰不會損害其他應用程式
  • 不影響作業系統完整性
  • 每個使用者不能訪問其他使用者資料(記憶體保護、訪問控制)

2.1.2 架構組成
  • UI主程序:頁面選項卡、外掛程序作為瀏覽器程序。


  • 渲染程序:特定選項卡作為渲染程序(渲染器),使用Blink(Webkit)開源佈局引擎解釋和佈局HTML。

2.1.3 渲染過程管理
  • RenderProcess:每個渲染程序都有一個全域性物件,管理與父瀏覽器的通訊並維護全域性狀態

  • RenderProcessHost:瀏覽器為每個渲染程序維護相應的渲染程序宿主,為每個渲染器管理瀏覽器狀態和IPC(IPC已棄用,最新用Mojo)通訊

  • RenderView:每個渲染程序有一或多個RenderView物件,對應內容選項卡。RenderProcessHost為渲染器的每個檢視(RenderView)維護一個RenderViewHost。每個檢視用一個ID區分。


2.1.4 執行流程
  • 渲染程序共享:開啟瀏覽器新視窗或新選項卡時,建立新的瀏覽器程序,並建立RenderView。不同頁面/iframe可共享同個渲染程序。

  • 崩潰監視:瀏覽器的IPC連線會監視程序控制代碼,如控制代碼對應的渲染程序已崩潰,會向標籤傳送通知,瀏覽器會顯示“悲傷標籤”

  • 沙箱執行:渲染器在單獨的程序中執行,通過沙箱限制其對系統資源(檔案、網路、顯示、擊鍵)的訪問,而須通過父瀏覽器程序訪問

  • 記憶體交回:程序最小化、隱藏的選項卡將其記憶體自動放入“可用記憶體”,記憶體不足時,windows會將該可用記憶體資料寫磁碟,記憶體被用於更高優先順序任務,以提高可見程式的響應速度。

2.1.5 外掛擴充套件
第三方編寫的NPAPI外掛因存在不穩定,同時需控制對系統資源的訪問,在各自獨立的程序中執行,與渲染器分開。

外掛設計文件:https://www.chromium.org/developers/design-documents/plugin-architecture

2.2 Webkit(Blink)架構
Blink是Web平臺的渲染引擎,實現了瀏覽器選項卡中呈現的內容:

  • HTML:實現Web平臺規範,HTML規範(DOM、CSS、Web IDL)
  • JavaScript:嵌入V8並執行JavaScript
  • 網路:從底層網路堆疊請求資源
  • 渲染:構建DOM樹,計算樣式和佈局,嵌入合成器並繪製圖形
  • 通過內容公共Api對外提供公共能力。

2.2.1 Blink的執行流程
多程序架構,有一個瀏覽器程序和N個沙盒渲染器程序,Blink在沙盒渲染中執行。瀏覽器選項卡、iframe可共享同個渲染器程序。

沙箱執行:在沙箱中,須通過父瀏覽器程序來排程使用資源(檔案訪問、網路、音視訊播放、使用者配置檔案讀取(cookie,密碼)等。Blink將瀏覽器程序抽象為一組服務,使用Mojo與服務、瀏覽器程序互動。

2.2.2  渲染程序中的執行緒
  • 1個主執行緒:執行JavaScript、DOM、CSS、樣式佈局計算
  • N個工作執行緒:執行Web Worker,ServiceWorker,Worklet
  • 內部執行緒:Blink和V8會建立幾個執行緒處理web audio,資料庫,GC等

跨執行緒通訊:使用PostTask API,不鼓勵共享記憶體程式設計除非效能原因。


2.2.3 Blink的執行和退出
  • 執行:任何使用Blink的場景都需呼叫 BlinkInitializer::Initialize() 初始化

  • 退出:渲染器被強制退出,而不會被清理


2.2.4 Blink的專案程式碼結構


  • platform:低階功能集合,如單片核心、幾何、圖形工具
  • core:core與DOM緊密結合
  • web:實現規範中的web平臺功能
  • modules:包含獨立的功能,如web audio,indexed db等。
  • bindings / core:大量使用V8 API
  • controller:一組使用core、modules的高階庫,如devtools。
  • 依賴關係:Chromium -> controller -> modules / bindings -> core / bindings -> platform -> 低階單元(base、V8、cc)


2.2.5 platform內部構成
1) WTF:統一編碼原語,如WTF::Vector, WTF::HashSet, WTF::HashMap, WTF::String and WTF::AtomicString來代替std:vector 等。

2) 記憶體管理:a. PartitionAlloc b.Oilpan(Blink GC) c.malloc/free/new/delete

3) 任務排程:為提高渲染引擎的響應,應執行非同步。所有任務都應釋出到Blink Scheduler任務佇列,指定正確型別並設定優先順序,以使得能巧妙地安排任務。

4) Page/Frame/Document/ExecutionContext/DOMWindow

分別對應選項卡、iframe、window.document、主執行緒和工作執行緒上下文、JavaScript中的視窗物件。

渲染程序中各種數量關係
  • 渲染器程序/Page = 1/N
  • 頁數/幀= 1/M
  • 框架/DOMWindow/文件(或ExecutionContext)= 1/1/1 (會隨時變化)

5) 程序外iframe
站點隔離:為每個站點建立一個渲染器程序(相同一二級域名)。跨站點由兩個渲染器託管。

6) 分離的iframe/檔案
doc = iframe.contentDocumentiframe.remove() //iframe 與 dom 樹分離doc.createElement('div'); //仍可在分離的框架上執行指令碼
左滑可檢視完整程式碼,下同

7) Web IDL繫結

8) V8
  • Isolate:一一對應物理執行緒。主執行緒、工作執行緒都有自己的獨立執行緒。
  • Context:對應全域性物件,如為Frame時對應Frame的視窗物件,每個幀都有自己的視窗物件
  • World:支援Chrome擴充套件程式內容指令碼

關係:一個frame = N個視窗物件 = 用於N個world。Context對應該視窗物件

V8的API低階且難以使用,在platform/bindings中提供很多V8 API輔助類。每個C++ DOM物件,如Node都有其對應的V8包裝器。V8包裝器對應的C++ DOM物件具有強引用。C++ DOM物件只對V8包裝器弱引用。


2.3 V8
V8是Google的開源高效能JavaScript和WebAssembly引擎,用C++編寫,它實現ECMAScript和WebAssembly,可獨立執行或嵌入到任何C++應用程式中,如Chrome和Node.js。
相關資料
ECMAScript:https://tc39.es/ecma262/ 
WebAssembly:https://webassembly.github.io/spec/core/ 

二、Chrome的多程序架構
注意:以下內容根據 Mariko Kosaka 的英文原版《Inside look at modern web browser》(見參考文獻),進行翻譯、理解、總結提煉、條理化、加入應用示例、進行相關知識補充擴充套件而來。


1. 背景:計算機的核心是CPU和GPU

CPU:Center Processing Unit,同時支援並行、序列操作,需很強通用性處理不同資料型別、要支援複雜通用邏輯判斷,需引入大量分支和中斷處理,結構異常複雜。

GPU:Graphics Processing Uint,專為執行圖形渲染必須的複雜的數學和幾何計算而設計。
圖片引自Mariko Kosaka的《Inside look at modern web browser》

圖片引自Mariko Kosaka的《Inside look at modern web browser》

三層計算機體系結構
圖片引自Mariko Kosaka的《Inside look at modern web browser》

2. 基礎:在Process和Thread執行程式

啟動應用程式時,建立一個程序,並提供”slab”記憶體,所有應用程式狀態儲存在該專用記憶體中,關閉程式時,系統釋放記憶體。

應用程式可能會建立多個執行緒完成工作任務。

圖片引自Mariko Kosaka的《Inside look at modern web browser》

圖片引自Mariko Kosaka的《Inside look at modern web browser》

3. 瀏覽器架構

瀏覽器架構沒有統一標準規範,不同瀏覽器可能使用不同執行緒或多個不同程序來構建web。少數執行緒間通過IPC通訊。

3.1 不同瀏覽器實現的體系結構

圖片引自Mariko Kosaka的《Inside look at modern web browser》

3.2 Chrome的多程序架構


圖片引自Mariko Kosaka的《Inside look at modern web browser》

4. 不同程序作用

  • 瀏覽器:控制應用程式chrome部分,包括位址列,書籤,後退和前進按鈕。及處理Web瀏覽器的不可見特權部分,例如網路請求和檔案訪問

  • 渲染:控制顯示網站的選項卡內的任何內容

  • 外掛:控制網站使用的任何外掛,例如flash。

  • GPU:獨立於其他程序處理GPU任務。它被分成不同的程序,因為GPU處理來自多個應用程式的請求並將它們繪製在同表面中。

  • 其他程序:瀏覽器右上角更多 -> 更多工具 -> 工作管理員,檢視其他程序,如實用程式網路服務、輔助框架

圖片引自Mariko Kosaka的《Inside look at modern web browser》

5. 多程序架構

優點:

  • 防一個頁面崩潰影響整個瀏覽器

  • 安全性和沙箱:作業系統提供了限制程序許可權的方法,因此瀏覽器可以從某些功能中對某些程序進行沙箱處理。如任意訪問檔案

  • 程序有自己的私有記憶體空間,可以擁有更多的記憶體。為了節省記憶體,Chrome限制了它可以啟動的程序數量。限制因裝置的記憶體和CPU功率而異,但當Chrome達到限制時,它會在一個程序中開始從同一站點執行多個選項卡

圖片引自Mariko Kosaka的《Inside look at modern web browser》

6. 服務化 - 節省更多記憶體

瀏覽器程式中相同的功能方法,正在將瀏覽器的每個部分作為一項服務執行,可以輕鬆拆分為不同程序或聚合成一個程序。

當Chrome在強大的硬體上執行時,它可能會將每個服務拆分為不同的流程,從而提供更高的穩定性,但如果它位於資源約束裝置上,Chrome會將服務整合到一個流程中,從而節省記憶體佔用。

Android的平臺上已經使用了類似的方法來整合流程以減少記憶體使用。

圖片引自Mariko Kosaka的《Inside look at modern web browser》


7. 給 Iframe分配單獨渲染程序 - 站點隔離

站點隔離:因不同站點之間共享記憶體空間會存在同源策略繞過(Meltdown and Spectre)安全問題:https://blog.csdn.net/wlmnzf/article/details/79319509%22%20/t%20%22_blank 。因此為每個跨網站iframe執行單獨的渲染器程序。

站點隔離難點:從根本上改變iframe的通訊方式,包括ctrl+F查詢、開啟devtools等需在不同渲染器程序訪問。【重大版本】。

圖片引自Mariko Kosaka的《Inside look at modern web browser》

三、頁面導航過程

1. 瀏覽器程序執行

多程序架構啟動多個程序處理不同的任務。選項卡外部的所有內容都由瀏覽器程序處理(包含UI執行緒、網路執行緒、儲存執行緒)。在位址列輸入url時,由瀏覽器程序的UI執行緒處理。

圖片引自Mariko Kosaka的《Inside look at modern web browser》


2. 處理輸入

當用戶開始輸入位址列時,UI執行緒需判斷是搜尋查詢還是URL。

  • 查詢:傳送到搜尋引擎


  • URL:請求URL的網站

3. 開始導航

使用者點選進入時:

  • 有註冊設定Service Worker從快取載入頁面,渲染程序中執行JavaScript程式碼,從快取載入頁面,無需請求網路


  • 未設定Service Worker時:

         1) UI執行緒啟動網路呼叫以獲取站點內容,選項卡載入轉圈


         2) 網路執行緒通過DNS查詢域名對應IP及建立http連線


         3) 網路執行緒接收處理301重定向頭。網路執行緒與請求重定向的UI執行緒通訊,啟動另一個URL請求


Service Worker

Service Worker註冊後,保留其範圍為參考。當導航時,網路執行緒根據註冊的範圍檢查域名,若url已註冊Service Worker,UI執行緒找到渲染程序執行ServiceWorker程式碼,從快取載入資料或從網路載入新資源。生命週期見:https://developers.google.com/web/fundamentals/primers/service-workers/lifecycle

導航預載入

如果ServiceWorker最終決定從網路請求資料,瀏覽器程序與渲染程序間的往返可能導致延時,通過與ServiceWorker啟動並行載入資源加速來減少延時,允許標記這些請求,允許伺服器決定為這些請求傳送不同的內容。

圖片引自上面ServiceWorker的生命週期

4. 讀取響應結果

4.1 確定檔案MIME型別

網路執行緒檢視流的前幾個位元組,響應頭中Content-Type頭確定MIME資料型別。因此資料可能丟失,因此用MIME嗅探方式來檢視資源。https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types

4.2 處理不同MIME檔案

響應檔案是HTML,則將資料傳遞給渲染器程序。如果為.zip或其他檔案則將資料傳遞給下載管理器。

4.3 安全檢查

  • 惡意名單檢查:如果域和響應資料在惡意站點名單中,則網路執行緒發出和顯示警告頁面。


  • 跨域讀取檢查:CrossOriginReadBlock檢查,敏感的跨站點資料不進入渲染器程序

5. 查詢渲染程序

所有檢查完成後,網路執行緒告知UI執行緒資料已準備就緒,UI執行緒找到渲染程序以繼續渲染網頁。

由於網路請求可能需要幾百毫秒才能得到響應,為加速此過程,在開始導航網路執行緒傳送url請求時,已經主動進行查詢、啟動渲染程序,資料接收完成後,渲染程序已備用。

6. 提交導航

現在資料和渲染器程序已準備就緒,IPC將從瀏覽器程序傳送到渲染程序以提交導航。渲染程序確認提交完成,導航完成。文件載入開始。

1、UI更新:位址列更新、安全指示器、站點設定UI會反映新頁面站點資訊

2、選項卡的會話歷史記錄更新(前進/後退),為便於關閉瀏覽器後恢復,歷史記錄到磁碟

7. 初始化 load complete

提交導航後,渲染器程序將繼續載入資源並呈現頁面,一旦渲染器程序“完成”(onload事件在所有幀上觸發執行完成後)渲染,它就會將IPC傳送回瀏覽器程序。

UI執行緒停止選項卡的載入轉圈。

8. 導航到其他站點

導航完成後,再次將不同的URL放到位址列導航,瀏覽器會檢查當前渲染網站的beforeunload事件。如有設定導航或關閉選項卡時發出警報“離開這個網站嗎?” 包含JavaScript程式碼的選項卡內的所有內容都由渲染程序處理。
渲染程序導航操作
單擊連結或客戶端JavaScript已執行window.location = “https://newsite.com“ ,過程與流程器程序啟動導航過程相同,不同點在於導航請求是從渲染程序啟動到瀏覽器程序。


頁面生命週期:https://developers.google.com/web/updates/2018/07/page-lifecycle-api#overview_of_page_lifecycle_states_and_events

圖片引自上面的頁面生命週期

四、頁面渲染

1. 渲染程序處理頁面內容

渲染程序負責選項卡內發生的所有事情。在渲染器程序中

  • 主執行緒:處理您傳送給使用者的大部分程式碼。

  • 工作執行緒:處理WebWorker或ServiceWorker

  • 排版執行緒:Compositor

  • 柵格執行緒
圖片引自Mariko Kosaka的《Inside look at modern web browser》

2. 解析

2.1 構建DOM

當渲染程序接收提交的導航訊息和HTML資料,主執行緒開始解析文字串(HTML),使之成為一個DOM。解析中遇到html能優雅容錯。

DOM:瀏覽器頁面內部表示,提供給開發人員通過JS與DOM互動的資料結構和API。

圖片引自Mariko Kosaka的《Inside look at modern web browser》


2.2 子資源載入

網站通常使用影象,CSS和JavaScript等外部資源,需要從網路或快取載入。在解析構建DOM時,主執行緒可以逐個請求它們。為了加快速度“預載入掃描器”同時執行。

2.3 JavaScript阻塞解析

當遇到
在看



熱點新聞