47 張圖帶你走進瀏覽器的世界!

大家好,我是零一,每個開發者(尤其是前端工程師)或多或少會跟瀏覽器打交道,那麼你們有沒有想過去深入瞭解瀏覽器呢?無論是因爲好奇還是爲了面試,相信你們一定在網上搜過不少關於瀏覽器相關的知識和文章,或者也買過不少的課程。但很少有文章能生動形象地帶你去了解瀏覽器的點點滴滴。

今天就給大家帶來一篇我同事 獨釣寒江雪 帶來的🔥萬字精品文章,他是思否的優秀作者,輸出多篇硬核文章,感興趣的朋友可以點擊文章末尾的「閱讀原文」進行查看~

作者:獨釣寒江雪

原文鏈接:https://juejin.cn/post/6983896089703235592

本文用47張圖帶你瞭解**「瀏覽器的發展史」**、**「瀏覽器的架構」**、**「瀏覽器的基本原理」**以及 **「瀏覽器的其它小知識」**

🚩 正文開始

瀏覽器的主要功能就是向服務器發出請求,在瀏覽器窗口中展示 HTML 文檔、PDF、圖片、視頻等網絡內容。這些網絡資源的位置由用戶使用 URI(統一資源標示符)來指定指定。

或許在大多數人眼中,瀏覽器是這樣的:

大多數人眼中的瀏覽器

「一個展示前端,一個未知的中間層連接着網絡世界」;甚至,網絡世界也可以省略:一臺顯示器,一個神祕的幕後黑盒。

如果你是一個前端開發者,甚至每天瀏覽器陪伴你度過的時光比女朋友陪伴你的都要久,想想那每一個令人 “不是那麼期待” 的早晨,每一個爭分奪秒完成任務的黃昏,只有瀏覽器和編輯器一直是你忠實的夥伴。而**「就連你一直離不開的 VS Code 編輯器,甚至也與瀏覽器有着莫大的淵源」**。

屏幕前的朋友,你熟悉自己身邊的那些人嗎,熟悉那些與你朝夕相伴的朋友嗎?也許熟悉,也許不,那麼,你是否願意花些時間來熟悉一下這個在大量時間裏與你有着莫大交集的瀏覽器的內心世界呢?

今天,我們就來一探究竟,走進這個我們與網絡連接最緊密的中間地帶。全文行文結構大概如下:

目錄結構

瀏覽器發展簡史

瀏覽器的誕生與發展

也許你知道,第一款瀏覽器 —— WorldWideWeb,誕生於 1990 年。但是現代瀏覽器的雛形卻孕育於 1980s 年代。

一位名叫蒂姆 · 伯納斯 - 李的英國科學家在 1980 年代初期創建了一個名爲 Inquire 的計算機程序,當時他在總部位於瑞士的歐洲核研究組織(CERN,以其法文字母表示)工作。該計劃旨在**「使在 CERN 工作的許多不同個人更容易共享信息」**。

1990 年,第一款瀏覽器問世於 Tim Berners-Lee 在 CERN 工作期間。您可能想知道 Web 瀏覽器到底是什麼,簡而言之,它是一個計算機程序,其目的是顯示和檢索數據。使用分配給存儲在網絡服務器上的每個數據集(網頁)的 URL,它可以做到這一點。所以這意味着**「當您在瀏覽器中輸入內容時,您實際上是在輸入地址」**,瀏覽器將使用該地址來獲取您想要查看的信息。**「瀏覽器的另一個關鍵功能是以易於理解的方式向您解釋和呈現計算機代碼」**。

下圖簡單羅列了截止 2020 年瀏覽器的發展簡史:

Timeline_of_the_Web_Browsers

早期比較有名、有意義的瀏覽器主要包括 Erwise、ViolaWWW、Mosaic、Netscape Navigator:

The-Early-Browsers

1990 年瀏覽器誕生之後的故事,想必您已經早有耳聞:

1995 年 8 月 9 日,網景公開募股,最初的價格是 14 美元一股,但後來陰差陽錯,改爲 28 美元一股發行,當天收盤時,網景的股票成了 75 美元一股,網景成爲了當時世界上市值最高的互聯網公司,Netscape 的 IPO 也助長了日益增長的網絡泡沫。

Market_Share_During_the_Browser_Wars

市場份額的快速下滑導致 Netscape 被出售給了 AOL,2003 年 7 月,網景解散,就在解散的當天,Mozilla 基金會成立,2004 年基於 Mozilla 源碼的 Firefox 首次登臺,拉開了第二次瀏覽器大戰的序幕。2008 年 Netscape 最終滅絕,「當年的瀏覽器帝國正式退出了歷史的舞臺」

到 2003 年,微軟的 Internet Explorer 控制了 92% 以上的市場,完全扭轉了 1995 年的局面。然而,雖然微軟在不到十年的時間裏成功地完全接管了瀏覽器市場,但很快就會出現其他競爭,再次重塑網絡瀏覽器的歷史。

瀏覽器市場份額

截止 2021 年 7 月初,瀏覽器市場份額如下所示。

瀏覽器使用趨勢變化:

Web_Browser_Usage_Trends

瀏覽器市場份額:

Web_Browser_Market_Share

國內瀏覽器市場份額:

Web_Browser_Market_Share_CHN

如果你對以上瀏覽器市場份額數據有興趣,可以通過以下鏈接進行查看:

瀏覽器架構

計算機的核心

三層計算機體系結構:底部是機器硬件,中間是操作系統,頂部是應用程序。

hw-os-app

當你在電腦或手機上啓動應用時,是 「CPU 和 GPU 爲應用供能」。通常情況下應用是通過操作系統提供的機制在 CPU 和 GPU 上運行。

CPU

中央處理器(Central Processing Unit),或簡稱爲 CPU。CPU 可以看作是計算機的大腦。「一個 CPU 核心如圖中的辦公人員,可以逐一解決很多不同任務」。它可以在解決從數學到藝術一切任務的同時還知道如何響應客戶要求。過去 CPU 大多是單芯片的。隨着現代硬件發展,你經常會有不止一個內核,爲你的手機和筆記本電腦提供更多的計算能力。

4 個 CPU 核心作爲辦公人員,坐在辦公桌前處理各自的工作:

CPU

GPU

圖形處理器(Graphics Processing Unit,簡稱爲 GPU)是計算機的另一部件。與 CPU 不同,GPU 擅長同時處理跨內核的簡單任務。顧名思義,「它最初是爲解決圖形而開發的」。這就是爲什麼在圖形環境中 “使用 GPU” 或 “GPU 支持” 都與快速渲染和順滑交互有關。近年來隨着 GPU 加速計算的普及,僅靠 GPU 一己之力也使得越來越多的計算成爲可能。

下圖中,許多帶特定扳手的 GPU 內核意味着它們只能處理有限任務。

GPU

進程與線程

進程可以被描述爲是一個應用的執行程序。線程是位於進程內部並執行其進程程序的任意部分。

啓動應用時會創建一個進程。程序也許會創建一個或多個線程來幫助它工作。操作系統爲進程提供了一個可以使用的 “一塊” 內存,所有應用程序狀態都保存在該私有內存空間中。關閉應用程序時,相應的進程也會消失,操作系統會釋放內存(下圖中,邊界框爲進程,線程作爲抽象魚在進程中游動)。

memory

進程可以請求操作系統啓動另一個進程來執行不同的任務。此時,內存中的不同部分會分給新進程。如果兩個進程需要對話,他們可以通過 ** 進程間通信(IPC)** 來進行。許多應用都是這樣設計的,所以如果一個工作進程失去響應,該進程就可以在不停止應用程序不同部分的其他進程運行的情況下重新啓動。

workerprocess.gif

瀏覽器的進程 / 線程架構模型

瀏覽器進程分類

關於如何**「構建 web 瀏覽器並不存在標準規範」**,一個瀏覽器的構建方法可能與另一個迥然不同。不同瀏覽器的進程 / 線程架構一般由下圖幾部分:

browser-arch

Chrome 多進程架構

而當下 “瀏覽器世界的王者” Chrome 架構如下圖所示,渲染進程下顯示了多個層,表明 Chrome 爲每個標籤頁運行多個渲染進程。

browser-arch-chrome

上圖中,頂部是瀏覽器進程,它與處理應用其它模塊任務的進程進行協調。對於渲染進程來說,創建了多個渲染進程並分配給了每個標籤頁。Chrome 在可能的情況下會給每個標籤頁分配一個進程。而現在它試圖給每個站點分配一個進程,包括 iframe。

可以簡單理解爲不同進程對應瀏覽器 UI 的不同部分:

browserui

「Chrome 更多的是把自己抽象爲一個操作系統,網頁或擴展相當於一個個程序」,你甚至可以發現,Chrome 確實自帶了一個任務管理器,在任務管理器面板會列出當前正在運行的進程以及它們當前的 CPU / 內存使用量情況等信息。

一般你可以通過兩種方法打開 Chrome 任務管理器:

task

前文中提到了 Chrome 使用多個渲染進程,那他有什麼優勢呢?

tabs.gif

由於進程有自己的私有內存空間,所以它們通常包含公共基礎設施的拷貝 (如 Chrome V8 引擎)。這意味着使用了更多的內存,如果它們是同一進程中的線程,就無法共享這些拷貝(同一個進程中的線程不共享堆棧,堆棧是保證線程獨立運行所必須的)。爲了節省內存,Chrome 對可啓動的進程數量有所限制。具體限制數值依設備可提供的內存與 CPU 能力而定,但是**「當 Chrome 運行時達到限制時,會開始在同一站點的不同標籤頁上運行同一進程」**。

Chrome 正在經歷架構變革,它轉變爲將瀏覽器程序的每一模塊作爲一個服務來運行,從而可以輕鬆實現進程的拆解或聚合。具體表現是,當 Chrome 運行在**「強力硬件」**上時,它會將每個服務分解到不同進程中,從而**「提升穩定性」**,但是如果 Chrome 運行在資源有限的設備上時,它會將服務聚合到一個進程中從而**「節省了內存佔用」**。在這一架構變革實現前,類似的整合進程以減少內存使用的方法已經在 Android 類平臺上使用。

servicfication.gif

Chrome 67 版本後,桌面版 Chrome 都默認開啓了**「站點隔離」**,每個標籤頁的 iframe 都有一個單獨的渲染進程。啓用站點隔離是多年來工程人員努力的結果。站點隔離並不只是分配不同的渲染進程這麼簡單。它從根本上改變了 iframe 的通信方式。在一個頁面上打開開發者工具,讓 iframe 在不同的進程上運行,這意味着開發者工具必須在幕後工作,以使它看起來無縫。即使運行一個簡單的 Ctrl + F 來查找頁面中的一個單詞,也意味着在不同的渲染器進程中進行搜索。你可以看到爲什麼**「瀏覽器工程師把發佈站點隔離功能作爲一個重要里程碑」**!

isolation

延伸閱讀:Chrome 爲什麼多進程而不是多線程?[4]

瀏覽器整體架構

如果您是一名前端工程師,那麼,面試時你大概率會被問到過:從 URL 輸入到頁面展現到底發生了什麼?,如果您對這一過程不太熟悉,建議看看下面兩篇文章,在此不過多贅述:

瀏覽器的主要任務之一就是渲染展示頁面,不同的瀏覽器內核,渲染過程也不完全相同,但大致流程都差不多,下面這張圖片是火狐瀏覽器(Firefox,可以認爲是 Netscapede 的涅槃重生)開發文檔中的一張圖片。

瀏覽器架構

上面這張圖片大體揭示了瀏覽器的渲染展示流程,但是從瀏覽器的整體架構上來說,上面的圖片展示的也許只是瀏覽器體系中的冰山一角。

通常意義下,瀏覽器架構是如下圖這樣的:

瀏覽器架構

用戶界面

包括地址欄、前進 / 後退按鈕、書籤菜單等。除了瀏覽器主窗口顯示的您請求的頁面外,其他顯示的各個部分都屬於用戶界面。

瀏覽器引擎

用戶界面和渲染引擎的橋樑,在用戶界面和渲染引擎之間傳送指令。瀏覽器引擎提供了開始加載 URL 資源 和一些其他高級操作方法,比如:重新加載、前進、後退動作,錯誤信息、加載進度等。

渲染引擎

負責顯示請求的內容。如果請求的內容是 HTML,它就負責解析 HTML 和 CSS 內容,並將解析後的內容顯示在屏幕上。

所謂瀏覽器內核就是指瀏覽器最重要或者說核心的部分 "Rendering Engine",譯爲 "渲染引擎"。負責對網頁語法的解析,比如 HTML、JavaScript,並渲染到網頁上。所以瀏覽器內核也就是瀏覽器所採用的渲染引擎,渲染引擎決定這瀏覽器如何顯示頁面的內容和頁面的格式信息。不同的瀏覽器內核對語法的解釋也不相同,因此同一網頁在不同內核的瀏覽器顯示的效果也會有差異(瀏覽器兼容)。這也就是網頁開發者在不需要同內核的瀏覽器中測試網頁顯示效果的原因。

RENDERING ENGINE

延伸閱讀:曾紅極一時的紅芯瀏覽器,官網對其介紹是:擁有智能的認證引擎、渲染引擎、管控引擎,而且還有強大的 “國密通訊協議”,支持統一管控、遠程控制。2018 年 8 月 15 日,紅芯瀏覽器被爆出打開安裝目錄後出現大量和谷歌 Chrome 瀏覽器一致的同名文件,其安裝程序的文件屬性中也顯示了原始文件名 chrome.exe,紅芯瀏覽器的官網已撤下了瀏覽器的下載鏈接。8 月 16 日,紅芯聯合創始人高婧迴應,紅芯瀏覽器 “包含‘Chrome’在裏面”,但並非抄襲,而是 “站在巨人的肩膀上去做創新”。

hongxin

言歸正傳,瀏覽器內核主要包括以下三個技術分支:排版渲染引擎、 JavaScript 引擎,以及其他。

排版引擎:

瀏覽器的內核引擎,基本上是四分天下:

需要略作補充的是,我們經常還會聽到 Chromium、Webkit2、Blink 這些引擎。

chromium 架構

圖片來源:萬字詳文:深入理解瀏覽器原理 [7]

各內核關係圖:

KHTML

下面我們以 WebKit 爲列,進行簡單介紹,以便讓你對渲染引擎有一個更多的理解。WebKit 由多個重要模塊組成,通過下圖我們可以對 WebKit 有個整體的瞭解:

WebKit

WebKit 就是一個**「頁面渲染以及邏輯處理引擎」**,前端工程師把 HTML、JavaScript、CSS 這 “三駕馬車” 作爲輸入,經過 WebKit 的處理,就輸出成了我們能看到以及操作的 Web 頁面。從上圖我們可以看出來,WebKit 由圖中框住的四個部分組成。而其中最主要的就是 WebCore 和 JSCore(或者是其它 JS 引擎)。除此之外,WebKit Embedding API 是負責瀏覽器 UI 與 WebKit 進行交互的部分,而 WebKit Ports 則是讓 Webkit 更加方便的移植到各個操作系統、平臺上,提供的一些調用 Native Library 的接口,比如在渲染層面,在 iOS 系統中,Safari 是交給 CoreGraphics 處理,而在 Android 系統中,Webkit 則是交給 Skia。

WebKit 的渲染流程:

WebKit-Rendering

首先瀏覽器通過 URL 定位到了一堆由 HTML、CSS、JS 組成的資源文件,通過加載器把資源文件給 WebCore。之後 HTML Parser 會把 HTML 解析成 DOM 樹,CSS Parser 會把 CSS 解析成 CSSOM 樹。最後把這兩棵樹合併,生成最終需要的渲染樹,再經過佈局,與具體 WebKit Ports 的渲染接口,把渲染樹渲染輸出到屏幕上,成爲了最終呈現在用戶面前的 Web 頁面。

網絡

用於網絡調用,比如 HTTP 請求。其接口與平臺無關,併爲所有平臺提供底層實現,負責網絡通信和安全。

JavaScript 解釋器

用於解析和執行 JavaScript 代碼,執行結果將傳遞給渲染引擎來展示。

用戶界面後端

用於繪製基本的窗口小部件,比如組合框和窗口。其公開了與平臺無關的通用接口,而在底層使用操作系統的用戶界面方法。

數據存儲

這是持久層,瀏覽器需要在硬盤上保存各種數據,例如 Cookie。新的 HTML 規範 (HTML5) 定義了 “網絡數據庫”,這是一個完整而輕便的瀏覽器內數據庫。

求同存異的瀏覽器架構

下面列出了部分瀏覽器的架構圖,也許有些架構已經改變,有興趣可以簡單參考看看,除了 IE 之外,大體上各瀏覽器的整體架構都是類似的。

Mosaic 架構:

Architecture_of_Mosaic

Firefox 架構:

Architecture_of_Mozilla

Chrome 架構:

Architecture_of_Chrome

Safari 架構:

Architecture_of_Safari

IE 架構:

IE 架構

瀏覽器基本原理

Chrome V8

V8 一詞最早見於 “V-8 engine”,即 V8 發動機,一般使用在中高端車輛上。8 個氣缸分成兩組,每組 4 個,成 V 型排列。是高層次汽車運動中最常見的發動機結構,尤其在美國,IRL,ChampCar 和 NASCAR 都要求使用 V8 發動機。

關於 Chrome V8,筆者曾有一篇筆記做了比較詳細的介紹,全文脈絡如下,感興趣可以參考閱讀 [8]。

Chrome-V8

V8 是依託 Chrome 發展起來的,後面確不侷限於瀏覽器內核。發展至今 V8 應用於很多場景,例如流行的 nodejs,weex,快應用,早期的 RN。V8 曾經歷過一次比較大的架構調整,主要變化在於 “從字節碼的放棄到真香”。

V8 的早期架構

V8 引擎誕生的使命就是要在速度和內存回收上進行革命。JavaScriptCore 的架構是採用生成字節碼的方式,然後執行字節碼。Google 覺得 JavaScriptCore 這套架構不行,生成字節碼會浪費時間,不如直接生成機器碼快。所以 V8 在前期的架構設計上是非常激進的,採用了直接編譯成機器碼的方式。後期的實踐證明 Google 的這套架構速度是有改善,但是同時也造成了**「內存消耗問題」**。

V8-2010

早期的 V8 有 Full-Codegen 和 Crankshaft 兩個編譯器。V8 首先用 Full-Codegen 把所有的代碼都編譯一次,生成對應的機器碼。JS 在執行的過程中,V8 內置的 Profiler 篩選出熱點函數並且記錄參數的反饋類型,然後交給 Crankshaft 來進行優化。所以 Full-Codegen 本質上是生成的是未優化的機器碼,而 Crankshaft 生成的是優化過的機器碼。

隨着網頁的複雜化,V8 也漸漸的暴露出了自己架構上的缺陷:

V8 的現有架構

爲了解決上述缺點,V8 借鑑 JavaScriptCore 的架構,生成字節碼。V8 採用生成字節碼的方式後,整體流程如下圖:

V8-2017

現在的 V8 是一個非常複雜的項目,有超過 100 萬行 C++ 代碼。它由許多子模塊構成,其中這 4 個模塊是最重要的:

採用新的 Ignition+TurboFan 架構後,比 Full-codegen+Crankshaft 架構內存降低一半多,且 70% 左右的網頁速度得到了提升。

在運行 C、C++ 以及 Java 等程序之前,需要進行編譯,不能直接執行源碼;但對於 JavaScript 來說,我們可以直接執行源碼 (比如:node test.js),它是在運行的時候先編譯再執行,這種方式被稱爲**「即時編譯 (Just-in-time compilation)」**,簡稱爲 JIT。因此,V8 也屬於 **「JIT 編譯器」**。

JavaScriptCore

V8 未誕生之前,早期主流的 JavaScript 引擎是 JavaScriptCore 引擎。JavaScriptCore(以下簡稱 JSCore)主要服務於 Webkit 瀏覽器內核,他們都是由蘋果公司開發並開源出來。JSCore 是 WebKit 默認內嵌的 JS 引擎,之所以說是默認內嵌,是因爲很多基於 WebKit 分支開發的瀏覽器引擎都開發了自家的 JS 引擎,其中最出名的就是前文提到的 Chrome 的 V8。這些**「JS 引擎的使命都是解釋執行 JS 腳本」**。而在渲染流程上,JS 和 DOM 樹之間存在着互相關聯,這是因爲瀏覽器中的 JS 腳本最主要的功能就是操作 DOM 樹,並與之交互。我們可以通過下圖看下它的工作流程:

JavaScriptCore

JavaScriptCore 主要模塊:「Lexer 詞法分析器,將腳本源碼分解成一系列的 Token;Parser 語法分析器,處理 Token 並生成相應的語法樹;LLInt 低級解釋器,執行 Parser 生成的二進制代碼;Baseline JIT 基線 JIT(just in time 實時編譯);DFG 低延遲優化的 JIT;FTL 高通量優化的 JIT」

可以看到,相比靜態編譯語言生成語法樹之後,還需要進行鏈接,裝載生成可執行文件等操作,解釋型語言在流程上要簡化很多。這張流程圖右邊畫框的部分就是 JSCore 的組成部分:Lexer(詞法分析)、Parser(語法分析)、LLInt 以及 JIT(解釋執行)的部分(之所以 JIT 的部分是用橙色標註,是因爲並不是所有的 JSCore 中都有 JIT 部分)。

PS:嚴格的講,語言本身並不存在編譯型或者是解釋型,因爲語言只是一些抽象的定義與約束,並不要求具體的實現,執行方式。這裏講 JS 是一門 “解釋型語言” 只是 JS 一般是被 JS 引擎動態解釋執行,而並不是語言本身的屬性。

如果對 JavaScriptCore 有更多興趣,關於 JavaScriptCore 的更多細節,建議延伸閱讀以下幾篇博文:

瀏覽器與 JavaScript

這一小結,還是以 Chrome V8 爲例,簡單闡述瀏覽器與 JavaScript 的關係。

「V8 出現之前,所有的 JavaScript 虛擬機所採用的都是解釋執行的方式,這是 JavaScript 執行速度過慢的一個主要原因」。而 V8 率先引入了**「即時編譯(JIT)** 的 ** 雙輪驅動」**的設計(混合使用編譯器和解釋器的技術),這是一種權衡策略,**「混合編譯執行和解釋執行這兩種手段」**,給 JavaScript 的執行速度帶來了極大的提升。V8 出現之後,各大廠商也都在自己的 JavaScript 虛擬機中引入了 JIT 機制,所以目前市面上 JavaScript 虛擬機都有着類似的架構。另外,**「V8 也是早於其他虛擬機引入了惰性編譯、內聯緩存、隱藏類等機制,進一步優化了 JavaScript 代碼的編譯執行效率」**。

V8 執行一段 JavaScript 的流程

V8 執行一段 JavaScript 的流程如下圖所示:

V8 執行一段 JavaScript 流程圖

結合上文介紹的 Chrome V8 架構,聚焦到 JavaScript 上,瀏覽器拿到 JavaScript 源碼,Parser,Ignition 以及 TurboFan 可以將 JS 源碼編譯爲彙編代碼,其流程圖如下:

V8 流程

簡單地說,Parser 將 JS 源碼轉換爲 AST,然後 Ignition 將 AST 轉換爲 Bytecode,最後 TurboFan 將 Bytecode 轉換爲經過優化的 Machine Code(實際上是彙編代碼)。

圖片中的紅色虛線是逆向的,也就是說 Optimized Machine Code 會被還原爲 Bytecode,這個過程叫做 「Deoptimization」。這是因爲 Ignition 收集的信息可能是錯誤的,比如 add 函數的參數之前是整數,後來又變成了字符串。生成的 Optimized Machine Code 已經假定 add 函數的參數是整數,那當然是錯誤的,於是需要進行 Deoptimization。

function add(x, y) {
  return x + y;
}

add(1, 2);
add('1''2');

「V8 本質上是一個虛擬機」,因爲計算機只能識別二進制指令,所以要讓計算機執行一段高級語言通常有兩種手段:

簡單總結如下,**「V8 執行一段 JavaScript 代碼所經歷的主要流程」**包括:

Chrome V8 的事件機制

關於異步編程和消息隊列,UI 線程提供一個消息隊列,並將待執行的事件添加到消息隊列中,然後 UI 線程會不斷循環地從消息隊列中取出事件、執行事件,通用 UI 線程宏觀架構如下圖所示:

v8-ui

瀏覽器的不同形態

WebView

「WebView 是一種嵌入式瀏覽器,原生應用可以用它來展示網絡內容」。WebView 只是一個**「可視化的」**組件 / 控件 / 微件等。這樣我們可以用它來作爲我們原生 app 的視覺部分。當你使用原生應用時,WebView 可能只是被隱藏在普通的原生 UI 元素中,你甚至用不到注意到它。

如果你把瀏覽器想象成兩部分,一部分是 UI(地址欄,導航欄按鈕等),其它部分是把標記跟代碼轉換成我們可見和可交互視圖的引擎。「WebView 就是瀏覽器引擎部分」,你可以像插入 iframe 一樣將 Webview 插入到你的原生應用中,並且編程化的告訴它將會加載什麼網頁內容。

運行在你的 WebView 中的 JavaScript 有能力調用原生的系統 API。這意味着你不必受到 Web 代碼通常必須遵守的傳統瀏覽器安全沙箱的限制。下圖解釋了使用這種技術後的架構差異:

webview and webapp

默認情況下,在 WebView 或 Web 瀏覽器中運行的任何 Web 代碼都與應用的其餘部分保持隔離。這樣做是出於安全原因,主要是爲降低惡意的 JavaScript 代碼對系統造成的傷害。對於任意 Web 內容,這種安全級別很有意義, 因爲你永遠不能完全信任加載的 Web 內容。但 WebView 的情況並非如此,對於 WebView 方案,開發人員通常可以完全控制加載的內容。惡意代碼進入並在設備上造成混亂的可能性非常低。

「這就是爲什麼對於 WebView,開發人員可以使用各種受支持的方式來覆蓋默認的安全行爲,並讓 Web 代碼和原生應用代碼相互通信。這種溝通通常稱爲 bridge」。你可以在上文的圖片中看到 bridge 可視化爲 Native Bridge 和 JavaScript Bridge 的一部分。

WebView 非常好,雖然它看起來像是完全特殊和獨特的,但請記住,它們只不過是一個在應用中設置好位置和大小的、沒有任何花哨 UI 的瀏覽器,這就是它的精髓。大多數情況下,除非您調用原生 API,否則您不必在 WebView 中專門測試您的 Web 應用程序。此外,您在 WebView 中看到的內容與您在瀏覽器中看到的內容相同,尤其是使用同一渲染引擎時:

WebView 的應用:

如果你對 WebView 感興趣,可通過以下幾篇文章繼續瞭解:

Headless browser

**「無頭瀏覽器」**是一種未配置圖形用戶界面 (GUI) 的 Web 瀏覽器,通常通過命令行或網絡通信來執行。它主要由軟件測試工程師使用,沒有 GUI 的瀏覽器執行速度更快,因爲它們不必繪製視覺內容。無頭瀏覽器的最大好處之一是它們能夠在沒有 GUI 支持的服務器上運行。

Headless 瀏覽器對於測試網頁特別有用,因爲它們能夠像瀏覽器一樣呈現和理解超文本標記語言,包括頁面佈局、顏色、字體選擇以及 JavaScript 和 AJAX 的執行等樣式元素,這些元素在使用其他測試方法時通常是不可用的。

Headless_architecture

Headless 瀏覽器有兩個主要可交付成果:

Architecture_of_Puppeteer

Puppeteer 是一個 Node 庫,他提供了一組用來操縱 Chrome 的 API, 通俗來說就是一個 headless chrome 瀏覽器 (當然你也可以配置成有 UI 的,默認是沒有的)。既然是瀏覽器,那麼我們手工可以在瀏覽器上做的事情 Puppeteer 都能勝任, 另外,Puppeteer 翻譯成中文是” 木偶” 意思,所以聽名字就知道,操縱起來很方便,你可以很方便的操縱她去實現:

1) 生成網頁截圖或者 PDF 2) 高級爬蟲,可以爬取大量異步渲染內容的網頁 3) 實現 UI 自動化測試,模擬鍵盤輸入、表單自動提交、點擊、登錄網頁等 4) 捕獲站點的時間線,以便追蹤你的網站,幫助分析網站性能問題 5) 模擬不同的設備 6) ...

Puppeteer 跟 webdriver 以及 PhantomJS 最大的 的不同就是它是站在用戶瀏覽的角度,而 webdriver 和 PhantomJS 最初設計就是用來做自動化測試的,所以它是站在機器瀏覽的角度來設計的,所以它們 使用的是不同的設計哲學。

Electron

Electron(原名爲 Atom Shell)是 GitHub 開發的一個開源框架。它通過使用 Node.js(作爲後端)和 Chromium 的渲染引擎(作爲前端)完成跨平臺的桌面 GUI 應用程序的開發。現已被多個開源 Web 應用程序用於前端與後端的開發,著名項目包括 GitHub 的 Atom 和微軟的 Visual Studio Code。

Electron

Electron Architecture 由多個 Render Process 和一個 Main 進程組成。Main Process 啓動 Render Process,它們之間的通信是通過 IPC [Inter Process Communication],如下圖所示。

Electron_Architecture

我們常用的 IDE VSCode 就是基於 Electron (原來叫 Atom Shell) 進行開發的。如下圖所示,(點擊 VSCode 幫助【Help】 下的 切換開發人員工具即可打開以下面板)。

VSCode

VS Code 的其他的主要組件有:

延伸閱讀:Electron | Build cross-platform desktop apps with JavaScript, HTML, and CSS[27]

瀏覽器代碼兼容性測試

延伸閱讀

參考資料

本文首發於個人博客 [44],歡迎指正和 star[45]。

參考資料

[1]

瀏覽器市場份額: https://link.juejin.cn/?target=https%3A%2F%2Ftongji.baidu.com%2Fresearch%2Fsite

[2]

全球瀏覽器市場份額: https://link.juejin.cn/?target=https%3A%2F%2Fgs.statcounter.com%2F

[3]

w3counter: https://link.juejin.cn/?target=https%3A%2F%2Fwww.w3counter.com%2Fglobalstats.php

[4]

Chrome 爲什麼多進程而不是多線程?: https://link.juejin.cn/?target=https%3A%2F%2Fwww.zhihu.com%2Fquestion%2F368712837

[5]

經典面試題:從 URL 輸入到頁面展現到底發生什麼?: https://link.juejin.cn/?target=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F57895541

[6]

在瀏覽器輸入 URL 回車之後發生了什麼(超詳細版): https://link.juejin.cn/?target=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F80551769

[7]

萬字詳文:深入理解瀏覽器原理: https://link.juejin.cn/?target=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F96986818

[8]

參考閱讀: https://link.juejin.cn/?target=https%3A%2F%2Fsegmentfault.com%2Fa%2F1190000037435824

[9]

Parser: https://link.juejin.cn/?target=https%3A%2F%2Fv8.dev%2Fblog%2Fscanner

[10]

Ignition: https://link.juejin.cn/?target=https%3A%2F%2Fv8.dev%2Fdocs%2Fignition

[11]

TurboFan: https://link.juejin.cn/?target=https%3A%2F%2Fv8.dev%2Fdocs%2Fturbofan

[12]

Orinoco: https://link.juejin.cn/?target=https%3A%2F%2Fv8.dev%2Fblog%2Ftrash-talk

[13]

深入理解 JSCore: https://link.juejin.cn/?target=https%3A%2F%2Ftech.meituan.com%2F2018%2F08%2F23%2Fdeep-understanding-of-jscore.html

[14]

深入剖析 JavaScriptCore: https://link.juejin.cn/?target=https%3A%2F%2Fming1016.github.io%2F2018%2F04%2F21%2Fdeeply-analyse-javascriptcore%2F

[15]

JavaScriptCore 全面解析: https://juejin.cn/post/6844903765582053384

[16]

深入淺出 JavaScriptCore: https://link.juejin.cn/?target=https%3A%2F%2Fwww.jianshu.com%2Fp%2Fac534f508fb0

[17]

7.5.1 WebView(網頁視圖) 基本用法: https://link.juejin.cn/?target=https%3A%2F%2Fwww.runoob.com%2Fw3cnote%2Fandroid-tutorial-webview.html

[18]

Android:這是一份全面 & 詳細的 Webview 使用攻略: https://link.juejin.cn/?target=https%3A%2F%2Fwww.jianshu.com%2Fp%2F3c94ae673e2a%2F

[19]

Headless Chrome architecture: https://link.juejin.cn/?target=https%3A%2F%2Fwww.cnblogs.com%2Fbigben0123%2Fp%2F13880254.html

[20]

puppeteer: https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fpuppeteer%2Fpuppeteer%2F

[21]

Puppeteer 入門教程: https://link.juejin.cn/?target=https%3A%2F%2Fwww.r9it.com%2F20171106%2Fpuppeteer.html

[22]

結合項目來談談 Puppeteer: https://link.juejin.cn/?target=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F76237595

[23]

Monaco Editor: https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2FMicrosoft%2Fmonaco-editor

[24]

Language Server Protocol: https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2FMicrosoft%2Flanguage-server-protocol

[25]

Debug Adapter Protocol: https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2FMicrosoft%2Fdebug-adapter-protocol

[26]

Xterm.js: https://link.juejin.cn/?target=https%3A%2F%2Fxtermjs.org%2F

[27]

Electron | Build cross-platform desktop apps with JavaScript, HTML, and CSS: https://link.juejin.cn/?target=https%3A%2F%2Fdelftswa.gitbooks.io%2Fdesosa2018%2Fcontent%2Felectron%2Fchapter.html

[28]

caniuse: https://link.juejin.cn/?target=https%3A%2F%2Fwww.caniuse.com%2F

[29]

browseemall: https://link.juejin.cn/?target=https%3A%2F%2Fwww.browseemall.com%2FResources

[30]

html5test: https://link.juejin.cn/?target=https%3A%2F%2Fhtml5test.com%2F

[31]

瀏覽器簡史: https://link.juejin.cn/?target=http%3A%2F%2Fwww.cnw.com.cn%2Fzhuanti%2F2009-ie%2F

[32]

Web 瀏覽器相關的一些概念: https://link.juejin.cn/?target=https%3A%2F%2Fkeqingrong.cn%2Fblog%2F2019-11-24-concepts-related-to-web-browsers

[33]

瀏覽器的工作原理:新式網絡瀏覽器幕後揭祕: https://link.juejin.cn/?target=https%3A%2F%2Fwww.html5rocks.com%2Fzh%2Ftutorials%2Finternals%2Fhowbrowserswork%2F

[34]

從瀏覽器多進程到 JS 單線程,JS 運行機制最全面的一次梳理: https://link.juejin.cn/?target=https%3A%2F%2Fsegmentfault.com%2Fa%2F1190000012925872

[35]

Inside look at modern web browser: https://link.juejin.cn/?target=https%3A%2F%2Fdevelopers.google.com%2Fweb%2Fupdates%2F2018%2F09%2Finside-browser-part1

[36]

Inside look at modern web browser: https://link.juejin.cn/?target=https%3A%2F%2Fdevelopers.google.com%2Fweb%2Fupdates%2F2018%2F09%2Finside-browser-part1

[37]

瀏覽器是如何工作的:Chrome V8 讓你更懂 JavaScript: https://link.juejin.cn/?target=https%3A%2F%2Fsegmentfault.com%2Fa%2F1190000037435824

[38]

深入理解 JSCore: https://link.juejin.cn/?target=https%3A%2F%2Ftech.meituan.com%2F2018%2F08%2F23%2Fdeep-understanding-of-jscore.html

[39]

The Story of the Web: A History Of Internet Browsers: https://link.juejin.cn/?target=https%3A%2F%2Fwww.internetadvisor.com%2Fthe-story-of-the-web-a-history-of-internet-browsers

[40]

PPT - Browser Architecture: https://link.juejin.cn/?target=https%3A%2F%2Fsangbui.com%2Fsb-files%2FBrowserArchitecture_ClientSide.pdf

[41]

JavaScript 引擎 V8 執行流程概述: https://link.juejin.cn/?target=http%3A%2F%2Fblog.itpub.net%2F69912579%2Fviewspace-2668277%2F

[42]

Understanding WebViews: https://link.juejin.cn/?target=https%3A%2F%2Fwww.kirupa.com%2Fapps%2Fwebview.htm

[43]

Quantum Up Close: What is a browser engine?: https://link.juejin.cn/?target=https%3A%2F%2Fhacks.mozilla.org%2F2017%2F05%2Fquantum-up-close-what-is-a-browser-engine%2F

[44]

個人博客: https://link.juejin.cn/?target=https%3A%2F%2Fking-hcj.github.io%2F2021%2F07%2F11%2Fweb-browser%2F

[45]

指正和 star: https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fking-hcj%2Fking-hcj.github.io

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/cnE9UaM5v8Q4rbKdB00KiA