微信公衆號:愛寫bugger的阿拉斯加
若有問題或建議,請後臺留言,我會盡力解決你的問題。
此文章是我最近在看的【WebKit 技術內幕】一書的一些理解和作的筆記。
而【WebKit 技術內幕】是基於 WebKit 的 Chromium 項目的講解。程序員
WebKit 的一個顯著特徵就是支持不一樣的瀏覽器,由於不一樣瀏覽器的需求不一樣,因此在 WebKit 中一些代碼 能夠共享,可是另一部分是不一樣的,這些不一樣的部分稱爲 WebKit 的移植( Ports )。
上圖的 WebKit 架構,虛線框表示該部分模塊在不一樣瀏覽器使用的 WebKit 內核中的實現是不一樣的,也就是它們 不是廣泛共享的。用實線框表示的部分,表示它們是基本上是共享的,但不是絕對,是由於它們中的一些特性可能並非共享的,並且能夠經過不一樣的編譯設置改變它們的行爲。web
圖中最下面的是操做系統,不一樣瀏覽器可能會依賴不一樣的操做系統,同一個瀏覽器使用的 WebKit 也可能依賴不一樣的的操做系統。數據庫
操做系統之上的就是 WebKit 賴以工做的衆多第三方庫,這些庫是 WebKit 運行的基礎。編程
在它們兩者之上的就是 WebKit 項目了。瀏覽器
WebCore 包含了了目前被 各個瀏覽器所使用的 WebKit 共享部分,這些都是加載和渲染網頁的基礎部分,它們必不可少,包括 HTML (解釋器)、CSS (解釋器)、SVG、DOM、渲染樹(RenderObject 樹和RenderLqyer 樹等),以及 Inspector(Web Inspector和調試網頁)。這些共享部分有些是基礎框架,其背後支持也須要各個平臺的不一樣實現。安全
JavaScriptCore 引擎是 WebKit 中默認 JavaScript 引擎,也就是說一些 WebKit 的移植使用該引擎。並且它只是默認,並非惟一的,是能夠替換的。事實上,WebKit 中對 JavaScript 引擎的調用是獨立於引擎的。在 Google 的 Chormium 開源項目中,它被替換成 V8 引擎。微信
WebKit Ports 指的是 WebKit 中的非共享部分,對於不一樣瀏覽器使用的 WebKit 來講,移植中的這些模塊因爲平臺差別、第三方庫和需求不一樣等緣由,每每按照本身的方式來設計與實現,這就產生了移植部分,這也是致使衆多 WebKit 版本的行爲並不是一到的重要緣由。這其中包括硬件的 加速架構,網絡棧,視頻解碼,圖片解碼等。網絡
在 WebCore 和 WebKit Ports 之上的層主要是提供嵌入式編程接口,這些接口是提供給瀏覽器調用(固然也能夠有其餘使用者)。圖中有左右兩個部分分別是狹義 WebKit 的接口和 WebKit2 的接口。由於接口與具體的移植有關,因此有一個與瀏覽器相關的綁定層。綁定層上面就是 WebKit 項目對外暴露的接口層。實際上接口層的定義也是與移植密切相關的,而不是 WebKit 有什麼統一接口。多線程
WebKit 還有一個部分在圖中沒有展示出來,那就是測試用例,包括佈局測試用例( Layout Tests )和性能測試用例( Performance Tests ),這兩類測試包括了大量的測試用例和指望結果。爲了保證 WebKit 的代碼質量,這些用例被用來驗證渲染結果的正確性。架構
Chromium 也是基於 WebKit ( Blink ) 的,並且在 WebKit 的移植部分中,因此能夠經過 Chromium 能夠了解如何基於 WebKit 構建瀏覽器。
在上面這些模塊之上的就是著名 的 "Content 模塊" 和 「Content API(接口)」,它們是 Chromium 對渲染網頁功能的抽象。"Content 模塊" 的本意是指網頁的內容,這裏是指用來渲染內容的模塊。若是沒有 Content 模塊,瀏覽器的開發者也能夠在 WebKit 的 Chormium 移植上渲染網頁內容,可是沒有辦法得到沙箱模型。跨進程的 GPU 硬件加速機制、衆多的 HTML5 功能,由於這些功能 不少是在 Content 層裏面實現的。
「Content 模塊」 和 「Content API」 將下面的渲染機制。安全機制和插件機制等隱藏起來,提供一個接口層。該接口目前被上層模塊或者其餘項目使用,內部 調用者包括 Chromium 瀏覽器、 Content Shell 等、外部包括 CEF (Chromium Embedded Framework)、Opera 瀏覽器等。
「Chromium 瀏覽器」 和 」Content Shell「 是構建在 Content API 之上的兩個 」瀏覽器「,Chromium 具備瀏覽器完整的功能,也就是咱們編譯出來能看到的瀏覽器式樣。而 」Content Shell「 是使用 Content API 來包裝的一層簡單的 」殼「,可是它也是一個簡單的 」瀏覽器「,用戶可使用 Content 模塊來渲染和顯示網頁內容。Content Shell 的做用很明顯,其一能夠用來測試 Content 模塊不少功能的正確性,例如渲染、硬件加速等。其二是一個參考,能夠被不少外部的項目參考來開發基於 」Content API「 的瀏覽器或者各類類型的項目。
在 Android 系統上, Content Shell 的做用更大,這是由於同它並排的左側的 」Chromium 瀏覽器「 部分的代碼根本就沒有開源,這直接致使開發者只能依賴 Content Shell。
」Android WebView「 是爲了知足 Android 系統上的 WebView 而設計的,其思想是利用 Chromium 的實現來替換原來 Android 系統默認的 WebView。
多進程模型至少帶來了三點好處:
一、避免因單個頁面不響應或者崩潰而影響整個瀏覽器的穩定性
二、當第三方插件崩潰時不會影響頁面或者瀏覽器的穩定性,這時由於第三方插件也被使用單獨的進程來運行
三、它方便了安全模型的實施,也就是說沙箱模型是基於多進程架構的。
Chromium 瀏覽器主要包括如下進程類型:
一、Browser 進程:瀏覽器的主進程,負責瀏覽器界面的顯示、各個頁面的管理、是全部其餘類型進程的祖先、負責它們的建立和銷燬等工做,它有且僅有一個。
二、Renderer 進程:網頁的渲染進程,負責頁面的渲染工做, Blink/WebKit 的渲染工做主要在這個進程中完成,可能有多個,可是 Renderer 進程的數量與用戶打開的網頁數量不必定一致,Chromium 設計了靈活的機制,容許用戶配置。此外,在沙箱模型啓動的狀況下,該進程可能會發生一些改變。
三、NPAPI 插件進程:該進程是爲 NPAPI 類型的插件而建立的。其建立的基本原則是每種類型的插件只會被建立一次,並且僅當使用時纔會被建立。當有多個網頁須要使用同一種類型的插件的時候,例如不少網頁須要使用 Flash 插件, Flash 插件的進程會爲每一個使用者建立一個實例,因此插件進程是被共享的。
四、GPU 進程: 最多隻有一個,當且僅當 GPU 硬件加速打開的時候纔會被建立,主要用於對 3D 圖形加速調用的實現。
五、Pepper 插件進程:同 NPAPI 插件進程,不一樣的是爲 Pepper 插件而建立的進程。
六、其餘類型的進程:圖中還有一些其餘類型的進程沒有描述出來,例如 Linux 下的 「Zygote」 進程,Renderer 進程其實都是由它建立而來。另一個就是名爲 「Sandbox」 的準備進程,這在安全機制中做進一步的介紹。
對於桌面系統(Windows、Liunx、Mac OS)中的 Chormium 的瀏覽器,它們的進程模型總結後包括如下一些特徵:
一、Browser 進程和頁面的渲染分開的,這保證了頁面的渲染致使的崩潰不會致使瀏覽器主界面的崩潰。
二、每一個網頁是獨立的進程,這保證了頁面之間相互不影響。
三、插件進程也是獨立的,插件自己的問題不會影響瀏覽器主界面和網頁
四、GPU 硬件加速進程也是獨立的。
Browser 進程和 Render 進程是如何利用 WebKit 渲染網頁的,這其中的代碼層次由圖 3-6 給出。
最下面的就是 WebKit 接口層,通常基於 WebKit 接口層的瀏覽器直接在上面構建,而沒有引入複雜的多進程架構。
而後,在 WebKit 接口層上面就是 Chromium 基於 WebKit 的接口層而引入黏附層,它的出現主要是由於 Chromium 中的一些類型和 WebKit 內部不一致,因此須要一個簡單的橋接層。
再上面的就是 Renderer,它主要是處理進程間通訊,接受來自Browser 進程的請求,並調用相應的 WebKit 接口層,同時,將 WebKit 的處理結果發送回去,上面這些介紹的層都是在 Renderer 進程中工做的。
下面就進入了 Browser 進程,與 Renderer 進程相對應的就是 RendererHost, 其目的也是處理同 Renderer 進程之間的通訊。不過 RendererHost 是給 Renderer 進程發送請求並接收來自 Renderer 進程的結果。
Web Contents 表示的就是網頁的內容,由於網頁可能有多個須要繪製的內容,例如彈出的對話框內容,因此這裏是 「Contents」。它同時包括顯示網頁內容的一個子窗口(在桌面系統上),這個子窗口最後被嵌入瀏覽器的用戶界面,做爲它的一個標籤頁。
每一個進程內部都有不少的線程。
多線程的主要目的就是爲了保持用戶界面的高響應度,保證 UI 線程(Browser進程中的主線程)不會被任何其餘費用時的操做阻礙從而影響了對用戶操做的響應。這些費時的其餘操做不少,例如本地文件讀寫、socket 讀寫、數據庫操做等。
既然文件讀寫等會阻礙其餘操做,因此把它們放在單獨的線程裏面本身忙或者等待去吧。而在 Renderer 進程中,Chromium 則不讓其餘操做阻止渲染線程的快速執行。爲了利用多核的優點,Chromium 將渲染過程管線化,這樣可讓渲染的階段在不一樣的線程執行。
網頁的加載和渲染過程在圖中模型下的基本工做方式如如下步驟:
一、Browser 進程收到用戶的請求,首先由 UI 線程處理,並且將相應的任務轉給 IO 線程,它隨即將該任務傳遞給 Renderer 進程。
二、Renderer 進程的 IO 線程通過簡單解釋後交給渲染線程。渲染線程接受請求,加載網頁並渲染網頁,這其中可能須要 Browser 進程獲取資源和須要 GPU 進程來幫助渲染,最後 Renderer 進程將結果由 IO 線程傳遞給 Browser 進程。
三、最後 Renderer 進程接收到結果並將結果繪製出來。
Content 接口不只提供了一層對多進程進行渲染的抽象接口,並且它從誕生以來一個重要的目標就是要支持全部的 HTML5 功能、GPU 硬件加速功能和沙箱機制,這可讓 Content 接口的使用都們不須要不少的工做便可獲得很強大的能力。
Content 接口按照功能分紅六個部分。每一個部分的接口通常也能夠分紅兩類,第一類是嵌入者(embedder,這裏能夠是 Chromium 瀏覽器、CEF3 和 Content Shell )調用的接口,另外一類是嵌入者應該實現的回調接口,被 Content 接口的內部實現所調用,用來參與具體實現的邏輯或者事件的監聽等。
相比於狹義的 WebKit ,WebKit2 是一套全新的結構和接口,而不是一個簡單的升級版。它的主要目的和思想同 Chromium 相似,就是將渲染過程放在單獨的進程中來完成,獨立於用戶界面。
依舊是自底向上介紹,WebKit2 中也引入了插件進程,並且它還引入了網絡進程。圖中的 「Web 進程」 對應於 Chromium 中的 Renderer 進程,主要是渲染網頁。在這之上的是 「UI 進程」,它對應於 Chromium 中的 Browser 進程。接口就是暴露在該進程中,應用程序只須要調用該接口便可。其中 「應用程序 」 指的是瀏覽器或者任何使用該接口的程序。
但願本文對你有點幫助。
對 全棧開發 有興趣的朋友能夠掃下方二維碼關注個人公衆號 —— 愛寫bugger的阿拉斯加
分享 web 開發相關的技術文章,熱點資源,全棧程序員的成長之路
陛下...看完奏摺,點個贊再走吧!