瀏覽器渲染引擎

背景

瀏覽器的內核中主要分爲渲染引擎和 javascript 引擎,本篇主要圍繞渲染引擎介紹一下瀏覽器的工做原理。javascript

首先,咱們先看幾個 user-agent 的字符串:html

  • Mozilla/ 1.0 (Windows NT 6.1;rv:2.0.1) Gecko/2010010Firefox/4.0.1
  • Mozilla/ 4. 0 (compatible; MSIE 7. 0; Windows NT 6. 0)
  • Mozilla/ 5. 0 (Linux; Android4. 0. 4; Galaxy Nexus Build/ IMM76B) AppleWebKit/ 535. 19 (KHTML, like Gecko) Chrome/ 18. 0. 1025. 133 Mobile Safari/ 535.

這是3個不一樣瀏覽器的 user-agent,第1個是Firefox的,第2個是IE7的,第3個是Chrome的。有沒有以爲很奇怪,爲何全部字符串的前面都會有一個 Mozilla 開頭呢? 並且在 Chrome 中包含了不少其餘瀏覽器的標識,Android,Gecko,Safari … , 這些瀏覽器廠商爲何要把這個user-agent字符串設計成這樣?user-agent 按照正常的理解就是瀏覽器的標識,包含操做系統和瀏覽器信息帶上版本號就好了,瀏覽器廠商爲何搞的這麼複雜呢?前端

這須要瞭解一下 user-agent 字符串歷史 ,大體的意思是, 早期的瀏覽器 Netscape 的 user-agent 是以 Mozilla/Version [Language] (Platform; Encryption) 的格式,大多數服務器在加載頁面前都會檢查 user-agent 是否爲該款瀏覽器,然而在 1995年, IE 發佈首款瀏覽器,若是不兼容Netscape user-agent 字串,用戶就根本訪問不了頁面,因而IE就設計了這種格式: Mozilla/2.0 (compatible; MSIE Version; Operating System) 。 其餘新的瀏覽器發佈也是同樣的,爲了溶入主流而不被踢出局,在 user-agent 字串中放詳盡的信息,以便騙取網站的信任使它與其它流行的瀏覽器兼容。java

接下來,簡單回顧一下瀏覽器的歷史:web

  • WorldWideWeb 1991 年
  • Mosaic 1993年
  • Netscape 1994年
  • Opera 1995年
  • IE 1995年 一戰
  • Safari 2003年
  • Firefox 2004年 二戰
  • Chrome 2008年
  • Edge 2015年

不少人都覺得最先的瀏覽器是 Netscape, 其實在 Netscape 以前還有 WorldWideWeb 和 Mosaic 兩個瀏覽器,WorldWideWeb 是世界上第一個瀏覽器,它同時也是一個編輯器,在 1991年發佈, 當時 http 的版本仍是 0.9 ,只支持 get 請求。編程

隨後在 1993年 由美國伊利諾州的伊利諾大學的 NCSA 組織,發佈第一個能夠顯示圖片的瀏覽器,叫 Mosaic。隨後 NCSA 將 Mosaic 的商業運營權轉售給了 Spyglass 公司,該公司又向包括微軟公司在內的多家公司技術受權,而後,微軟的IE瀏覽器就是從這裏開始了。canvas

1994年,在 Mosaic 瀏覽器開發團隊的核心成員,從新成立 Netscape 公司,今後 Netscape 瀏覽器誕生。瀏覽器

1995年,挪威的本土電信公司 Telenor 開發了一個新的瀏覽器 Opera,Opera 瀏覽器他特色就是速度快,可是兼容性不是很好,在瀏覽器上首創了不少功能,好比標籤式瀏覽就是 Opera 發明的,Opera 在經歷不少坎坷後,在 2016 年被奇虎 360 收購。安全

1995同年,微軟在取得 Spyglass Mosaic 的源代碼和受權後,發佈了首款瀏覽器 Internet Explorer ,今後展開瀏覽器第一次大戰。服務器

1998年,Netscape 公司內部成立Mozilla組織。

2003年,蘋果公司發佈了本身第一個瀏覽器 Safari,同時在兩年後,也就是 2005 年開源了本身的瀏覽器內核 Webkit。

2004年,Mozilla 組織發佈了 Firefox 瀏覽器,而後第二次瀏覽器大戰開始。

2008年,是一個災難不少的一年,四川大地震,過年回家又趕上雪災,做爲前端開發個人將要開始兼容一個由 Goolge 開發新的 Chrome 瀏覽器。 可是 Chrome 帶來的體驗是讓人開心的 。

2015年,微軟隨着 Windows 10 一塊兒發佈 Edge 瀏覽器,傷透你們心的 IE ,估計維護不下去。

當前市場瀏覽器市場佔比最高的是 Chrome 瀏覽器,其次就是 IE,Firefox ,詳細佔比查看 Net Marketshare 的統計。

瀏覽器內核

內核 瀏覽器 出生年份 JS 引擎 開源
Trident IE4 - IE11 1997 JScript,chakra(ie9+)
Gecko Firefox 2004 SpiderMonkey MPL
WebKit Safari,Chromium,Chrome(-2013) ,Android瀏覽器,ChromeOS,WebOS 等 2005 JavascriptCore BSD
Blink Chrome, Opera 2013 V8 GPL
Edge Edge 2015 Chakra MIT(chakra)

市面上的瀏覽器都有本身的內核,有些內核之間還存一些關係。 WebKit 是 Apple 公司在 2005年開源的一個內核,Apple 公司早期使用的引擎是 KHTML,KHTML 是 KDE 社區維護,Apple 技術團隊也參與 KHTML 的開發,可是在開發過程當中,KDE 社區不太喜歡 Apple 團隊人員提交的代碼。因此 Apple 公司的人就本身獨立出來,在 KHTML 基礎之上建立了 WebKit 內核,並在 2005 年開源。 在 2008年,Google 發佈 Chrome 瀏覽器,採用的也是 Webkit 內核,同時技術團隊人員也參與 WebKit 項目的開發,可是在設計上與 Apple 團隊存在分歧,因此 Google 的人就獨立出來,基於 WebKit 開發了 Blink 內核,Blink 在 Webkit 的基礎上加入多進程,沙箱等不少技術。

回過頭看看國內,有不少瀏覽器,很牛逼,都是多核的,想要兼容國內銀行系統就切換到 Trident 內核,想要訪問速度就切換到 Webkit 內核,Blink 發佈之後,就把 WebKit 換成了 Blink 。

  • QQ瀏覽器 Trident+Webkit (Blink)
  • 360安全瀏覽器 Trident+Webkit (Blink)
  • 獵豹瀏覽器 Trident+Webkit (Blink)
  • 世界之窗 Trident+Webkit (Blink)
  • 搜狗高速瀏覽器 Trident+Webkit (Blink)
  • UC瀏覽器 Trident+Webkit (Blink)
  • ....

WebKit 架構

接下來咱們進入到 Webkit 裏面,首先看一下 WebKit 的架構圖

enter image description here

在上圖中實線部分,也就是 WebCore,基本上在各個瀏覽器中是共享的,虛線部分在各個瀏覽器中的存在差別。 WebCore 是渲染引擎,包含的 HTML 解釋器,CSS 解釋器,處理頁面佈局渲染等功能。 JavascriptCore 就是 WebKit 內置的 Javascript 引擎。 在最上層是 WebKit 嵌入式接口,這些接口提供給瀏覽器調用,可是咱們能夠看到圖中有 WebKit 和 WebKit2 兩個嵌入式接口,這兩有什麼區別呢?

WebKit 2 是 2010年4月份發佈的,抽象出一組新的編程接口,給開發者用,同時採用了多進程:,一個UI 進程,處理Web平臺與瀏覽器接口的進程,另一個 Web 進程, Web 頁面渲染的進程。 讓 web 進程與 UI 進程隔離,在健壯性、安全性以及更好地使用多核 cpu 等方面帶來了好處。 如下是WebKit 和 WebKit2的對比圖:

enter image description here

enter image description here

更多詳細信息能夠閱讀: https://trac.webkit.org/wiki/WebKit2

在 Javascript 旁邊有很大一塊區域是 Webkit Port,所謂 WebKit Port,並無確切的形式,能夠看做是OS,平臺(應用程序框架),Javacsript 引擎,以及各類第三方庫的一個組合。WebKit Port 提供不一樣的 Port 接口供外部程序使用,

以 Webkit 爲核心存在不少移植:

  • Apple's Mac Port
  • Apple's Windows Port
  • Cairo-based Windows Port
  • JSCOnly Port
  • WebKitGTK+ Port
  • QTWebKit
  • ...

WebKit Port 一般處於如下幾種目的:

  • 使用WebKit做爲瀏覽器(或者相似的User Agent)的頁面解析,排版和渲染的核心,如Safari,Chrome
  • 對WebKit進行封裝,對外提供構建一個瀏覽器(或者相似的UA)的API接口,如Qt
  • 以上二者皆有,如Android,iOS,BlackBerry

不一樣的 port 關注點不同

  • Mac 的 port 注意力集中在瀏覽器和操做系統的分割,它經過 Obj-C 和 C++ 代碼把(WebKit)渲染引擎嵌入到本地應用中。
  • Chromium port 專一在瀏覽器。
  • QtWebKit 則把它的 WebKit 實現做爲一個運行時的庫或者渲染引擎,同其跨平臺 GUI 應用程序框架一塊兒提供給其它應用使用。 好比 無頭瀏覽器 Phantomjs 就是基於 QtWebKit 實現的。

更多詳細信息能夠閱讀:https://trac.webkit.org/wiki#WebKitPorts

接下來,咱們來看一下基於 Chromium port 的瀏覽器。

enter image description here

在圖中咱們能夠看到左下角是 WebKit 內核,和他平級的還有:

  • GPU/Command Buffer , Command Buffer 是 GPU 線程的通訊媒介,提供GPU 硬件加速。
  • V8,Javascript 引擎
  • 沙箱模型,瀏覽器安全保護的一種設計
  • CC(Chromium 合成器),對 RenderLayer Tree 分紅渲染
  • IPC,UI,PPAPI ...

在上面一層是 Content , 若是沒有 Content, 也能正常渲染,不過上面提到的這些GPU 加速,沙箱模型,HTML 5等功能將沒有,Content API 提供了公開穩定的接口, 目標是支持全部的 HTML5功能和GPU硬件加速等功能。

「Chromium瀏覽器」 和 「ContentShell」 是構建在 ContentAPI 之上的兩個「瀏覽器」,Chromium具備瀏覽器完整的功能,也就是咱們編譯出來能看到的瀏覽器式樣。而「ContentShell」是使用ContentAPI來包裝的一層簡單的「殼」,可是它也是一個簡單的「瀏覽器」,用戶可使用Content模塊來渲染和顯示網頁內容。 ContentShell的做用很明顯,其一能夠用來測試Content模塊不少功能的正確性,例如渲染、硬件加速等;其二是一個參考,能夠被不少外部的項目參考來開發基於「ContentAPI」的瀏覽器或者各類類型的項目。

在 Android 系統上,ContentShell 的做用更大,這是由於同它並排的左側的 「Chromium瀏覽器」 部分的代碼根本就沒有開源,這直接致使開發者只能依賴ContentShell。

「Android WebView」,它是爲了知足Android系統上的 WebView 而設計的,其思想是利用Chromium的實現來替換原來Android系統默認的 WebView。

渲染過程

如下是瀏覽器渲染引擎及依賴模塊

enter image description here

一個渲染引擎主要包括HTML解釋器、CSS解釋器、佈局和JavaScript引擎等,JavaScript引擎如今都已經獨立出來。 下面是所依賴的模塊,包括網絡,存儲,2D/3D 圖形,音頻和視頻,圖片解碼器等等…, 再下面就是操做系統相關的支持。

一個大體的渲染過程及依賴模塊關係圖以下:

enter image description here

接下來咱們再來看一下,在 WebKit 的渲染的詳細過程:

enter image description here

首先是在瀏覽器輸入 URL 之後,依賴網絡模塊加載各類資源,獲得一個HTML , HTML 交給 HTML 解析器進行解析,最後生成 DOM 樹,若是再解析過程當中有存在 Javascript 代碼就交給 Javascript 引擎處理,處理完成返回給 DOM 樹, 這個環節的主要目的就是構建一個DOM 樹。

而後看一下 DOM樹到繪製上下文

enter image description here

在網絡資源中得到 CSS 代碼之後,會把 CSS 交給 CSS 解析器處理,同時會計算佈局。 DOM 樹會構建成一個 RenderObject 樹,它和 DOM 樹節點是一一對應,而後再和 解析後的CSS 合併分析,生成 RenderLayer 樹, 這個樹就是最終用於渲染的樹,而後繪製上下文。

如下是在網上找到的幾張圖,簡單解釋了 DOM 樹到 RenderLayer 樹最終的過程。

enter image description here

這一段簡單的 HTML 代碼,其中包含的 body, div canvas script 等元素,經過 HTML,CSS 解析器進行解析,最終會生成一個 RenderLayer 樹, 前面在Chromium 架構圖的時候有提到 CC 合成器,隨着GPU硬件能力的加強,包括在不少小型設備上也是如此,瀏覽器能夠藉助於其處理圖形方面的性能來對渲染實現加速。此時再也不將全部層繪製到一塊兒,而是進行分層渲染,合成以後再顯示到屏幕上。

enter image description here

如下 RenderLayer 樹的結構,從圖中能夠看出整個樹分了 3 個 Layer,在 Layer 下面包含了 RenderBlock,RenderText 等 Render 節點,每一個節點上都包含的座標,大小,以及背景顏色等渲染依賴的信息。

enter image description here

RenderBlock 其實就是咱們 HTML 中的塊級元素,咱們都知道一個元素是否爲塊級元素是能夠經過 CSS 改變的,因此,一個 RenderLayer 樹的結構也會根據CSS的變化變化,若是影響到元素的位置發生變化會都在整個樹從新計算,也是就是咱們說的迴流。 關於迴流的解釋能夠參考 : https://www-archive.mozilla.org/newlayout/doc/reflow.html 。

最後咱們簡單瞭解一下 Shadow DOM, 在前端開發過程當中你們都知道 React, Vue 這些框架中有組件的概念,一個頁面中存在不少重複的組件,在一個組件內部又存在不少基礎的 HTML 元素,這些元素能夠組成一顆DOM樹的子樹。這樣一個組件能夠被處處使用,可是問題隨之而來,那就是每一個使用組件的地方都會知道這個子樹的結構。當網頁的開發者須要訪問網頁DOM樹的時候,這些控件內部的DOM子樹都會暴露出來,這些暴露的節點不只可能給DOM樹的遍歷帶來不少麻煩,並且也可能給CSS的樣式選擇帶來問題,由於選擇器無心中可能會改變這些內部節點的樣式,從而致使很奇怪的界面。

那有什麼辦法能夠把這些內部節點封裝起來?就像咱們寫 javascript 模塊化同樣,W3C 工做組提出了 Shadow DOM 的概念,好比在 HTML5 支持的 <Video> 等標籤,在其內部有不少複雜的結構, 可是播放,暫停等按鈕咱們在 DOM 樹中沒法直接找到相應的節點,這其實就是 Shadow DOM 的思想。 Shadow DOM 是能夠經過 Javascript 自定義建立,在其內部能夠維護本身的DOM, CSS ,事件等, 具備很好的密封性。 自定義 Shadow DOM 目前只有 Chrome 支持,不過,我相信在不遠的未來 Shadow DOM 會給組件化開發帶來更多美好的體驗。

參考資料

  • 《WebKit 技術內幕》
  • 瀏覽器解密篇 http://www.nowamagic.net/academy/part/48/115/#
  • WebKit Wiki https://trac.webkit.org/wiki

原文地址: http://blog.hypers.io/2018/04/04/webkit-render/

相關文章
相關標籤/搜索