小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

用了十幾年的瀏覽器,你卻只會瀏覽

 蘇醒的貝殼 2019-08-17

導語:本文從市面主流的瀏覽器及相應的內(nèi)核引擎開始,介紹了Chromium為代表的瀏覽器架構(gòu)及Blink內(nèi)核的功能架構(gòu)。Chromium為多進程架構(gòu),用戶從啟動運行瀏覽器后,先后經(jīng)過頁面導航、渲染、資源加載、樣式計算、布局、繪制、合成到柵格化,最后完成GPU展示。而頁面渲染完成后,瀏覽器如何響應頁面操作事件也進行了深入的介紹。良心推薦!

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

用了十幾年的瀏覽器,你卻只會瀏覽

一、瀏覽器概論

瀏覽器經(jīng)歷了很多年的發(fā)展,瀏覽器引擎也在不停地迭代和演進。從PC時代到移動端,以獨立瀏覽器的形態(tài)還是以系統(tǒng)WebView組件內(nèi)嵌的形態(tài)存在,在互聯(lián)網(wǎng)的生態(tài)系統(tǒng)中一直扮演著重要的角色。了解瀏覽器及其原理可以讓我們打開另一個世界。

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層面實現(xiàn)進程隔離與Google的沙箱設計存在沖突。

3) Blink:基于Webkit2分支,13年谷歌開始作為Chrome 28的引擎集成在Chromium瀏覽器里。Android的WebView同樣基于Webkit2。

1.2 微軟瀏覽器

目前PC場景操作系統(tǒng)仍是windows一統(tǒng)天下,對桌面用戶來說,雖然IE的市場份額在下降,但是IE曾經(jīng)也風光過。IE內(nèi)核以Trident為主,最新的Edge也兼容了Chromium內(nèi)核。

Microsoft Edge:內(nèi)核為:EDGE,Windows 10默認瀏覽器,不能單獨下載安裝。兼容Chromium內(nèi)核,同時保留EDGE內(nèi)核來兼容企業(yè)網(wǎng)站

  • 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. 瀏覽器架構(gòu)

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

用了十幾年的瀏覽器,你卻只會瀏覽

以下為架構(gòu)的介紹:

  • 操作系統(tǒng):WebKit可以運行在不同的操作系統(tǒng)上,如Chromium瀏覽器支持Windows、Linux、Android等系統(tǒng);
  • 第三方庫:這些庫是WebKit運行的基礎,包括2D圖形庫、3D圖形庫、網(wǎng)絡庫、存儲庫、音視頻庫等;
  • WebCore:WebKit加載和渲染網(wǎng)頁的基礎,是不同瀏覽器所使用的WebKit中共享的部分,包括HTML解析器、CSS解析器、SVG、布局、渲染樹等等;
  • JavaScript引擎:JavaScript解析器,WebKit默認的引擎是JavaScriptCore,Google的Blink為V8引擎;
  • WebKit Ports:WebKit中的移植部分,包括網(wǎng)絡棧、音視頻解碼、硬件加速等模塊,這部分對WebKit的功能和性能影響比較大。
  • WebKit嵌入式接口:WebKit對外暴露的接口層,這個接口是提供給瀏覽器調(diào)用的,如給chromium調(diào)用,因為接口與具體的移植也有關(guān)系,所以中間會有一個WebKit綁定層

JavaScriptCore(用于Safari)

  • JavaSript Parser,JSON Parser
  • 字節(jié)編譯器:使用內(nèi)部字節(jié)碼格式
  • 匯編程序:在運行時使用代碼修補 - >它需要可寫代碼內(nèi)存
  • 數(shù)據(jù)流圖:基于編譯時推測優(yōu)化生成代碼的新舉措
  • 解釋器:運行生成的字節(jié)碼
  • Regexp引擎:支持JIT
  • 垃圾收集器:標記和掃描
  • 運行時:所有JS全局對象(日期,字符串,數(shù)字等)
  • 調(diào)試器,Profiler

WebCore

  • 資源加載器:HTML和XML解析器,DOM
  • SVG和SMIL
  • CSS:分析器,選擇器,動畫
  • 渲染和布局
  • 綁定生成器:IDL文件:JSC,V8,ObjC
  • HTML5:音頻,視頻,畫布,WebGL,通知功能
  • WebInspector
  • 平臺集成:圖形,字體,聲音,視頻

相關(guān)資料

  • Blink內(nèi)核:https://src./viewvc

2.1 多進程架構(gòu)

用了十幾年的瀏覽器,你卻只會瀏覽

圖片引自chromium-design-doc

https://www./developers/design-documents/multi-process-architecture

2.1.1 Chromium多進程架構(gòu)

早期的web瀏覽器頁面行為不當、瀏覽器錯誤、瀏覽器插件錯誤都會引起整個瀏覽器或當前運行的選項卡關(guān)閉。因此將chromium應用程序放在相互隔離的獨立的進程中:

  • 單個程序崩潰不會損害其他應用程序
  • 不影響操作系統(tǒng)完整性
  • 每個用戶不能訪問其他用戶數(shù)據(jù)(內(nèi)存保護、訪問控制)

2.1.2 架構(gòu)組成

  • UI主進程:頁面選項卡、插件進程作為瀏覽器進程。
  • 渲染進程:特定選項卡作為渲染進程(渲染器),使用Blink(Webkit)開源布局引擎解釋和布局HTML。

2.1.3 渲染過程管理

  • RenderProcess:每個渲染進程都有一個全局對象,管理與父瀏覽器的通信并維護全局狀態(tài)
  • RenderProcessHost:瀏覽器為每個渲染進程維護相應的渲染進程宿主,為每個渲染器管理瀏覽器狀態(tài)和IPC(IPC已棄用,最新用Mojo)通信
  • RenderView:每個渲染進程有一或多個RenderView對象,對應內(nèi)容選項卡。RenderProcessHost為渲染器的每個視圖(RenderView)維護一個RenderViewHost。每個視圖用一個ID區(qū)分。

2.1.4 運行流程

  • 渲染進程共享:開啟瀏覽器新窗口或新選項卡時,創(chuàng)建新的瀏覽器進程,并創(chuàng)建RenderView。不同頁面/iframe可共享同個渲染進程。
  • 崩潰監(jiān)視:瀏覽器的IPC連接會監(jiān)視進程句柄,如句柄對應的渲染進程已崩潰,會向標簽發(fā)送通知,瀏覽器會顯示“悲傷標簽”
  • 沙箱運行:渲染器在單獨的進程中運行,通過沙箱限制其對系統(tǒng)資源(文件、網(wǎng)絡、顯示、擊鍵)的訪問,而須通過父瀏覽器進程訪問
  • 內(nèi)存交回:進程最小化、隱藏的選項卡將其內(nèi)存自動放入“可用內(nèi)存”,內(nèi)存不足時,windows會將該可用內(nèi)存數(shù)據(jù)寫磁盤,內(nèi)存被用于更高優(yōu)先級任務,以提高可見程序的響應速度。

2.1.5 插件擴展

第三方編寫的NPAPI插件因存在不穩(wěn)定,同時需控制對系統(tǒng)資源的訪問,在各自獨立的進程中運行,與渲染器分開。

插件設計文檔:https://www./developers/design-documents/plugin-architecture

2.2 Webkit(Blink)架構(gòu)

Blink是Web平臺的渲染引擎,實現(xiàn)了瀏覽器選項卡中呈現(xiàn)的內(nèi)容:

  • HTML:實現(xiàn)Web平臺規(guī)范,HTML規(guī)范(DOM、CSS、Web IDL)
  • JavaScript:嵌入V8并運行JavaScript
  • 網(wǎng)絡:從底層網(wǎng)絡堆棧請求資源
  • 渲染:構(gòu)建DOM樹,計算樣式和布局,嵌入合成器并繪制圖形
  • 通過內(nèi)容公共Api對外提供公共能力。

2.2.1 Blink的運行流程

多進程架構(gòu),有一個瀏覽器進程和N個沙盒渲染器進程,Blink在沙盒渲染中運行。瀏覽器選項卡、iframe可共享同個渲染器進程。

沙箱運行:在沙箱中,須通過父瀏覽器進程來調(diào)度使用資源(文件訪問、網(wǎng)絡、音視頻播放、用戶配置文件讀取(cookie,密碼)等。Blink將瀏覽器進程抽象為一組服務,使用Mojo與服務、瀏覽器進程交互。

2.2.2 渲染進程中的線程

  • 1個主線程:運行JavaScript、DOM、CSS、樣式布局計算
  • N個工作線程:運行Web Worker,ServiceWorker,Worklet
  • 內(nèi)部線程:Blink和V8會創(chuàng)建幾個線程處理web audio,數(shù)據(jù)庫,GC等

跨線程通信:使用PostTask API,不鼓勵共享內(nèi)存編程除非性能原因。

用了十幾年的瀏覽器,你卻只會瀏覽

2.2.3 Blink的運行和退出

  • 運行:任何使用Blink的場景都需調(diào)用 BlinkInitializer::Initialize() 初始化
  • 退出:渲染器被強制退出,而不會被清理

2.2.4 Blink的項目代碼結(jié)構(gòu)

用了十幾年的瀏覽器,你卻只會瀏覽

  • platform:低級功能集合,如單片內(nèi)核、幾何、圖形工具
  • core:core與DOM緊密結(jié)合
  • web:實現(xiàn)規(guī)范中的web平臺功能
  • modules:包含獨立的功能,如web audio,indexed db等。
  • bindings / core:大量使用V8 API
  • controller:一組使用core、modules的高級庫,如devtools。
  • 依賴關(guān)系:Chromium -> controller -> modules / bindings -> core / bindings -> platform -> 低級單元(base、V8、cc)

2.2.5 platform內(nèi)部構(gòu)成

1) WTF:統(tǒng)一編碼原語,如WTF::Vector, WTF::HashSet, WTF::HashMap, WTF::String and WTF::AtomicString來代替std:vector 等。

2) 內(nèi)存管理:a. PartitionAlloc b.Oilpan(Blink GC) c.malloc/free/new/delete

3) 任務調(diào)度:為提高渲染引擎的響應,應執(zhí)行異步。所有任務都應發(fā)布到Blink Scheduler任務隊列,指定正確類型并設置優(yōu)先級,以使得能巧妙地安排任務。

4) Page/Frame/Document/ExecutionContext/DOMWindow

分別對應選項卡、iframe、window.document、主線程和工作線程上下文、JavaScript中的窗口對象。

渲染進程中各種數(shù)量關(guān)系
  • 渲染器進程/Page = 1/N
  • 頁數(shù)/幀= 1/M
  • 框架/DOMWindow/文檔(或ExecutionContext)= 1/1/1 (會隨時變化)

5) 進程外iframe

站點隔離:為每個站點創(chuàng)建一個渲染器進程(相同一二級域名)??缯军c由兩個渲染器托管。

6) 分離的iframe/文件

doc = iframe.contentDocumentiframe.remove() //iframe 與 dom 樹分離doc.createElement('div'); //仍可在分離的框架上運行腳本

左滑可查看完整代碼,下同

7) Web IDL綁定

8) V8

  • Isolate:一一對應物理線程。主線程、工作線程都有自己的獨立線程。
  • Context:對應全局對象,如為Frame時對應Frame的窗口對象,每個幀都有自己的窗口對象
  • World:支持Chrome擴展程序內(nèi)容腳本

關(guān)系:一個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++編寫,它實現(xiàn)ECMAScript和WebAssembly,可獨立運行或嵌入到任何C++應用程序中,如Chrome和Node.js。

用了十幾年的瀏覽器,你卻只會瀏覽

相關(guān)資料ECMAScript:https:///ecma262/ WebAssembly:https://webassembly./spec/core/

二、Chrome的多進程架構(gòu)

注意:以下內(nèi)容根據(jù) Mariko Kosaka 的英文原版《Inside look at modern web browser》(見參考文獻),進行翻譯、理解、總結(jié)提煉、條理化、加入應用示例、進行相關(guān)知識補充擴展而來。

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

CPU:Center Processing Unit,同時支持并行、串行操作,需很強通用性處理不同數(shù)據(jù)類型、要支持復雜通用邏輯判斷,需引入大量分支和中斷處理,結(jié)構(gòu)異常復雜。

GPU:Graphics Processing Uint,專為執(zhí)行圖形渲染必須的復雜的數(shù)學和幾何計算而設計。

用了十幾年的瀏覽器,你卻只會瀏覽

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

用了十幾年的瀏覽器,你卻只會瀏覽

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

用了十幾年的瀏覽器,你卻只會瀏覽

三層計算機體系結(jié)構(gòu)

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

2. 基礎:在Process和Thread執(zhí)行程序

啟動應用程序時,創(chuàng)建一個進程,并提供”slab”內(nèi)存,所有應用程序狀態(tài)保存在該專用內(nèi)存中,關(guān)閉程序時,系統(tǒng)釋放內(nèi)存。

應用程序可能會創(chuàng)建多個線程完成工作任務。

用了十幾年的瀏覽器,你卻只會瀏覽

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

用了十幾年的瀏覽器,你卻只會瀏覽

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

3. 瀏覽器架構(gòu)

瀏覽器架構(gòu)沒有統(tǒng)一標準規(guī)范,不同瀏覽器可能使用不同線程或多個不同進程來構(gòu)建web。少數(shù)線程間通過IPC通信。

3.1 不同瀏覽器實現(xiàn)的體系結(jié)構(gòu)

用了十幾年的瀏覽器,你卻只會瀏覽

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

3.2 Chrome的多進程架構(gòu)

用了十幾年的瀏覽器,你卻只會瀏覽

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

4. 不同進程作用

  • 瀏覽器:控制應用程序chrome部分,包括地址欄,書簽,后退和前進按鈕。及處理Web瀏覽器的不可見特權(quán)部分,例如網(wǎng)絡請求和文件訪問
  • 渲染:控制顯示網(wǎng)站的選項卡內(nèi)的任何內(nèi)容
  • 插件:控制網(wǎng)站使用的任何插件,例如flash。
  • GPU:獨立于其他進程處理GPU任務。它被分成不同的進程,因為GPU處理來自多個應用程序的請求并將它們繪制在同表面中。
  • 其他進程:瀏覽器右上角更多 -> 更多工具 -> 任務管理器,查看其他進程,如實用程序網(wǎng)絡服務、輔助框架

用了十幾年的瀏覽器,你卻只會瀏覽

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

5. 多進程架構(gòu)

優(yōu)點:

  • 防一個頁面崩潰影響整個瀏覽器
  • 安全性和沙箱:操作系統(tǒng)提供了限制進程權(quán)限的方法,因此瀏覽器可以從某些功能中對某些進程進行沙箱處理。如任意訪問文件
  • 進程有自己的私有內(nèi)存空間,可以擁有更多的內(nèi)存。為了節(jié)省內(nèi)存,Chrome限制了它可以啟動的進程數(shù)量。限制因設備的內(nèi)存和CPU功率而異,但當Chrome達到限制時,它會在一個進程中開始從同一站點運行多個選項卡

用了十幾年的瀏覽器,你卻只會瀏覽

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

6. 服務化 - 節(jié)省更多內(nèi)存

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

當Chrome在強大的硬件上運行時,它可能會將每個服務拆分為不同的流程,從而提供更高的穩(wěn)定性,但如果它位于資源約束設備上,Chrome會將服務整合到一個流程中,從而節(jié)省內(nèi)存占用。

Android的平臺上已經(jīng)使用了類似的方法來整合流程以減少內(nèi)存使用。

用了十幾年的瀏覽器,你卻只會瀏覽

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

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

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

站點隔離難點:從根本上改變iframe的通信方式,包括ctrl+F查找、打開devtools等需在不同渲染器進程訪問?!局卮蟀姹尽俊?/p>

用了十幾年的瀏覽器,你卻只會瀏覽

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

三、頁面導航過程

1. 瀏覽器進程運行

多進程架構(gòu)啟動多個進程處理不同的任務。選項卡外部的所有內(nèi)容都由瀏覽器進程處理(包含UI線程、網(wǎng)絡線程、存儲線程)。在地址欄輸入url時,由瀏覽器進程的UI線程處理。

用了十幾年的瀏覽器,你卻只會瀏覽

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

2. 處理輸入

當用戶開始輸入地址欄時,UI線程需判斷是搜索查詢還是URL。

  • 查詢:發(fā)送到搜索引擎
  • URL:請求URL的網(wǎng)站

3. 開始導航

用戶點擊進入時:

  • 有注冊設置Service Worker從緩存加載頁面,渲染進程中運行JavaScript代碼,從緩存加載頁面,無需請求網(wǎng)絡
  • 未設置Service Worker時:

1) UI線程啟動網(wǎng)絡調(diào)用以獲取站點內(nèi)容,選項卡加載轉(zhuǎn)圈

2) 網(wǎng)絡線程通過DNS查找域名對應IP及建立http連接

3) 網(wǎng)絡線程接收處理301重定向頭。網(wǎng)絡線程與請求重定向的UI線程通信,啟動另一個URL請求

Service Worker

Service Worker注冊后,保留其范圍為參考。當導航時,網(wǎng)絡線程根據(jù)注冊的范圍檢查域名,若url已注冊Service Worker,UI線程找到渲染進程執(zhí)行ServiceWorker代碼,從緩存加載數(shù)據(jù)或從網(wǎng)絡加載新資源。生命周期見:https://developers.google.com/web/fundamentals/primers/service-workers/lifecycle

導航預加載

如果ServiceWorker最終決定從網(wǎng)絡請求數(shù)據(jù),瀏覽器進程與渲染進程間的往返可能導致延時,通過與ServiceWorker啟動并行加載資源加速來減少延時,允許標記這些請求,允許服務器決定為這些請求發(fā)送不同的內(nèi)容。

用了十幾年的瀏覽器,你卻只會瀏覽

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

4. 讀取響應結(jié)果

4.1 確定文件MIME類型

網(wǎng)絡線程查看流的前幾個字節(jié),響應頭中Content-Type頭確定MIME數(shù)據(jù)類型。因此數(shù)據(jù)可能丟失,因此用MIME嗅探方式來查看資源。https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types

4.2 處理不同MIME文件

響應文件是HTML,則將數(shù)據(jù)傳遞給渲染器進程。如果為.zip或其他文件則將數(shù)據(jù)傳遞給下載管理器。

4.3 安全檢查

  • 惡意名單檢查:如果域和響應數(shù)據(jù)在惡意站點名單中,則網(wǎng)絡線程發(fā)出和顯示警告頁面。
  • 跨域讀取檢查:CrossOriginReadBlock檢查,敏感的跨站點數(shù)據(jù)不進入渲染器進程

5. 查找渲染進程

所有檢查完成后,網(wǎng)絡線程告知UI線程數(shù)據(jù)已準備就緒,UI線程找到渲染進程以繼續(xù)渲染網(wǎng)頁。

由于網(wǎng)絡請求可能需要幾百毫秒才能得到響應,為加速此過程,在開始導航網(wǎng)絡線程發(fā)送url請求時,已經(jīng)主動進行查找、啟動渲染進程,數(shù)據(jù)接收完成后,渲染進程已備用。

6. 提交導航

現(xiàn)在數(shù)據(jù)和渲染器進程已準備就緒,IPC將從瀏覽器進程發(fā)送到渲染進程以提交導航。渲染進程確認提交完成,導航完成。文檔加載開始。

1、UI更新:地址欄更新、安全指示器、站點設置UI會反映新頁面站點信息

2、選項卡的會話歷史記錄更新(前進/后退),為便于關(guān)閉瀏覽器后恢復,歷史記錄到磁盤

7. 初始化 load complete

提交導航后,渲染器進程將繼續(xù)加載資源并呈現(xiàn)頁面,一旦渲染器進程“完成”(onload事件在所有幀上觸發(fā)執(zhí)行完成后)渲染,它就會將IPC發(fā)送回瀏覽器進程。

UI線程停止選項卡的加載轉(zhuǎn)圈。

8. 導航到其他站點

導航完成后,再次將不同的URL放到地址欄導航,瀏覽器會檢查當前渲染網(wǎng)站的beforeunload事件。如有設置導航或關(guān)閉選項卡時發(fā)出警報“離開這個網(wǎng)站嗎?” 包含JavaScript代碼的選項卡內(nèi)的所有內(nèi)容都由渲染進程處理。

渲染進程導航操作單擊鏈接或客戶端JavaScript已運行window.location = “https://“ ,過程與流程器進程啟動導航過程相同,不同點在于導航請求是從渲染進程啟動到瀏覽器進程。

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

用了十幾年的瀏覽器,你卻只會瀏覽

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

四、頁面渲染

1. 渲染進程處理頁面內(nèi)容

渲染進程負責選項卡內(nèi)發(fā)生的所有事情。在渲染器進程中

  • 主線程:處理您發(fā)送給用戶的大部分代碼。
  • 工作線程:處理WebWorker或ServiceWorker
  • 排版線程:Compositor
  • 柵格線程

用了十幾年的瀏覽器,你卻只會瀏覽

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

2. 解析

2.1 構(gòu)建DOM

當渲染進程接收提交的導航消息和HTML數(shù)據(jù),主線程開始解析文本串(HTML),使之成為一個DOM。解析中遇到html能優(yōu)雅容錯。

DOM:瀏覽器頁面內(nèi)部表示,提供給開發(fā)人員通過JS與DOM交互的數(shù)據(jù)結(jié)構(gòu)和API。

用了十幾年的瀏覽器,你卻只會瀏覽

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

2.2 子資源加載

網(wǎng)站通常使用圖像,CSS和JavaScript等外部資源,需要從網(wǎng)絡或緩存加載。在解析構(gòu)建DOM時,主線程可以逐個請求它們。為了加快速度“預加載掃描器”同時運行。

2.3 JavaScript阻塞解析

當遇到<script>時,暫停HTML解析,加載解析執(zhí)行JS代碼。因為JS可能會改變Html的結(jié)構(gòu)導致重新reflow和repaint。

解析模型見:https://html.spec./multipage/parsing.html#overview-of-the-parsing-model

V8相關(guān)討論:https:///notes/shapes-ics

用了十幾年的瀏覽器,你卻只會瀏覽

3. 確定加載資源方式

  • 在<script>加async或defer屬性,瀏覽器異步加載和運行JS,不阻止解析。

1) async:指示瀏覽器盡可能異步加載腳本,默認同步加載腳本(async=false)

2) defer:指示腳本要在解析文檔之后但在觸發(fā)DOMContentLoaded之前執(zhí)行。

  • 用JS模塊化
  • 樣式文件中加rel=preload
  • 可設置資源加載優(yōu)先級,優(yōu)化加載渲染關(guān)鍵路徑資源,優(yōu)化性能。見:https://developers.google.com/web/fundamentals/performance/resource-prioritization

用了十幾年的瀏覽器,你卻只會瀏覽

上面圖片引自https://v/features/modules

4. 樣式計算

主線程解析CSS并確定每個DOM節(jié)點的計算樣式,再根據(jù)CSS選擇器將哪種樣式應用于哪個元素。

用了十幾年的瀏覽器,你卻只會瀏覽

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

未提供任何樣式時,每個DOM節(jié)點都具有默認的Computed樣式。見:https://cs./chromium/src/third_party/blink/renderer/core/html/resources/html.css

5. 布局 - layout

渲染進程知道每個節(jié)點的文檔結(jié)構(gòu)和樣式。布局是查找元素幾何的過程。

1) 布局過程

主線程 遍歷DOM并計算樣式,并創(chuàng)建布局樹(layout tree, 包含坐標和邊界框大小等信息)。

布局樹的特殊情況

  • 不包括display: none的節(jié)點
  • 包括visibility: hidden的元素
  • 包括偽類元素,如::before

用了十幾年的瀏覽器,你卻只會瀏覽

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

確定頁面布局的挑戰(zhàn):
  • 從上到下的塊流須考慮字體的大小以及在哪里劃分它們,最終影響段落的大小和形狀,影響下一段的位置
  • CSS可以使元素浮動到一側(cè),屏蔽溢出項,并更改寫入方向

6. 繪制 - Paint

知道元素的大小,形狀和位置,但是不知道繪制的順序。主線程遍歷布局樹以創(chuàng)建繪制記錄,繪制記錄是繪畫過程的一個注釋。

用了十幾年的瀏覽器,你卻只會瀏覽

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

渲染中的難點
  • 布局樹變化:在每個步驟中,前一個操作的結(jié)果用于創(chuàng)建新數(shù)據(jù)。例如,如果布局樹中的某些內(nèi)容發(fā)生更改,則需要為文檔的受影響部分重新生成“繪制”順序。

用了十幾年的瀏覽器,你卻只會瀏覽

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

用了十幾年的瀏覽器,你卻只會瀏覽

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

  • 動畫:在每個幀之間運行這些操作。大多數(shù)顯示器每秒刷新屏幕60次(60 fps),當你在每一幀移動屏幕時,動畫對人眼來說會很平滑(視覺停留效應)。但是如果動畫錯過了兩者之間的幀或程序運行JS時,則頁面將出現(xiàn)卡頓。

例如用時間不確定的 setTimeout() 只會更新內(nèi)存中的屬性變化,由于期間隔時間和屏幕刷新時間不同步,可能導致某些幀的操作被跨躍,直接更新下一幀的圖像。

用了十幾年的瀏覽器,你卻只會瀏覽

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

用了十幾年的瀏覽器,你卻只會瀏覽

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

用了十幾年的瀏覽器,你卻只會瀏覽

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

解決方法

  • 將JS操作劃分成小塊,并安排在每個幀上運行 window.requestAnimationFrame(renderFunc)。兼容版本:https://github.com/darius/requestAnimationFrame

優(yōu)點:

1) 省CPU時間:頁面隱藏最小化時停止渲染,setTimeout持續(xù)運行。

2) 函數(shù)節(jié)流:高頻率事件(resize/scroll)為防止刷新間隔內(nèi)多次執(zhí)行函數(shù),只執(zhí)行一次更流暢,省開銷。

// 節(jié)流(throttle) + 去抖(debounce)// 把要執(zhí)行的函數(shù)放在延時器中執(zhí)行且只執(zhí)行最后一次,且判斷距上次執(zhí)行的時間大于延時執(zhí)行時間 function show() {} let lastTime = new Date();let delay = 200;let timer = null;document.body.onscroll = function () { if (document.documentElement.scrollTop >= 1000) { let now = new Date(); if (now - lastTime > delay) { // 去抖 timer = setTimeout(show, 200); } else { clearTimeout(timer); // 節(jié)流 timer = setTimeout(show, 200); }  lastTime = new Date(); }};
  • 將非dom操作的運行任務放在webWorker中運行,避免阻塞主線程
// 任務文件 demo_workers.jsvar i = 0; function timedCount() { i = i + 1; postMessage(i); // 向頁面發(fā)送數(shù)據(jù)}setInterval(timedCount, 500); // 包含dom的頁面 index.htmllet w = new window.Worker('demo_workers.js'); // 開始w.onmessage = function (event) { document.getElementById('result').innerHTML = event.data;}; w.terminate(); // 停止

7. 合成

瀏覽器知道文檔的結(jié)構(gòu),每個元素的樣式,頁面的幾何形狀和繪制順序,需將信息轉(zhuǎn)換為屏幕上的像素,稱為光柵化。

在視口內(nèi)部使用柵格部件 - chrome首次發(fā)布時處理柵格化的方式用戶滾動頁面,則移動光柵框架,并通過更多光柵填充缺失的部分

合成是一種將頁面的各個部分分層,分別柵格化,并在合成器線程的單獨線程中合成為頁面的技術(shù)。如果發(fā)生滾動,圖層已經(jīng)被柵格化需要合成一個新幀。通過移動圖層和合成新幀,可以以相同的方式實現(xiàn)動畫。

7.1 分層

為了找出哪些元素需要在哪些層中,主線程遍歷布局樹以創(chuàng)建層樹。如果頁面的某些部分應該是單獨的圖層(如滑入式側(cè)面菜單)但沒有得到單獨圖層,可以使用CSS屬性will-change提示瀏覽器。https://developer.mozilla.org/zh-CN/docs/Web/CSS/will-change

過多的圖層:過多圖層合成可能會導致比頁面小部分每幀光柵化更慢。

用了十幾年的瀏覽器,你卻只會瀏覽

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

7.2 光柵和復合關(guān)閉主線程

1) 提交合成:一旦創(chuàng)建了層樹并確定了繪制順序,主線程就會將該信息提交給合成器線程。

2) 柵格化:合成器線程然后柵格化每個層。一個圖層可能像頁面的整個長度一樣大,因此合成器線程將它們分成多個圖塊并將圖塊發(fā)送到柵格線程。

3) 柵格存儲:柵格線程柵格化每個圖塊并將它們存儲在GPU內(nèi)存中。

4) 繪制四邊形:一旦圖塊被光柵化,繪制四邊形的圖塊信息(圖塊在內(nèi)存中的位置、繪制圖塊頁面中的位置)

5) 合成框架:合成器線程可以優(yōu)先考慮視口(或附近)內(nèi)的刪格線程,以便優(yōu)先被光柵化。圖層還有不同分辨率的傾斜度,可以處理放大操作。

6) 創(chuàng)建合成器幀:收集繪制四邊形的圖塊信息,通過IPC將合成器框架提交給瀏覽器進程

7) 瀏覽器UI合成:UI線程添加另一個合成器框架以用于瀏覽器UI更改,或者從其他渲染器進程添加擴展。

8) GPU展示:合成器幀被發(fā)送到GPU以在屏幕上顯示。

9) 滾動事件:合成器線程會創(chuàng)建另一個合成器幀以發(fā)送到GPU

用了十幾年的瀏覽器,你卻只會瀏覽

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

創(chuàng)建磁貼位圖并發(fā)送到GPU的柵格線程

用了十幾年的瀏覽器,你卻只會瀏覽

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

合成器線程創(chuàng)建合成框架,將名稱發(fā)送到瀏覽器進程然后發(fā)送到GPU

合成的好處
  • 不涉及主線程的情況下完成

  • 合成線程不需要等待樣式計算或JavaScript執(zhí)行。

因此合成動畫 被認為是平滑性能的最佳選擇。如果需要再次計算布局或繪圖,則必須涉及主線程。

五、頁面操作

1. 接收輸入事件

1) 瀏覽器進程接收 鍵入、鼠標事件、觸摸手勢等輸入事件。瀏覽器進程僅知道手勢發(fā)生位置,選項卡內(nèi)部內(nèi)容由渲染進程處理。

2) 瀏覽器進程將事件類型、坐標發(fā)送給渲染進程

3) 渲染進程通過查找事件目標并運行附加的事件偵聽器來適當?shù)靥幚硎录?/p>

用了十幾年的瀏覽器,你卻只會瀏覽

4) 合成器接入輸入事件

2. 非快速可滾動區(qū)域

1) 合成頁面時,合成器線程標記頁面的一個區(qū)域,該區(qū)域?qū)⑹录幚沓绦蚋郊訛椤胺强焖倏蓾L動區(qū)域”。

2) 通過獲取此信息,合成器線程可以確保在該區(qū)域中發(fā)生事件時將輸入事件發(fā)送到運行JavaScript的主線程。如果輸入事件來自該區(qū)域之外,則合成器線程在不等待主線程的情況下繼續(xù)合成新幀。

用了十幾年的瀏覽器,你卻只會瀏覽

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

3. 事件處理

下面程序中,整個頁面都被標記為非快速可滾動區(qū)域,合成器線程也必須與主線程通信,并在每次輸入事件進入時等待它,最終影響合成器平滑滾動能力。

document.body.addEventListener('touchstart', event = > { if (event.target === area) { event.preventDefault(); }});

解決方案

在事件監(jiān)聽器中傳遞 passive: true 選項,提示瀏覽器在主線程中監(jiān)聽事件,合成器線程也可以繼續(xù)合成新幀。

document.body.addEventListener( 'touchstart', event = > { if (event.target === area) { event.preventDefault(); }}, { passive: true});

4. 檢查取消事件

通過 event.cancelable和event.preventDefault()檢查取消事件。也可通過CSS來完全消除事件處理程序。

document.body.addEventListener( 'pointermove', event = > { if (event.cancelable) { event.preventDefault(); }}, { passive: true});
#area { touch - action: pan - x;}

5. 查找event.target

當合成器線程向主線程發(fā)送輸入事件時,首先要運行的是命中測試以查找事件目標。命中測試使用在渲染過程中生成的繪制記錄數(shù)據(jù)來找出事件發(fā)生的點坐標下面的內(nèi)容。

用了十幾年的瀏覽器,你卻只會瀏覽

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

6. 最小化事件派發(fā)到主線程

  • 屏幕刷新率:60 次/秒
  • 觸摸屏觸摸事件:60-120次/秒
  • 鼠標:100次/秒

輸入事件具有比屏幕刷新更高的保真度。主線程中觸發(fā)過快的連續(xù)事件,會觸發(fā)過多的命中測試和JS執(zhí)行,導致頁面抖動。為減少對主線程過度調(diào)用,Chrome合并連續(xù)事件(如 wheel,mousewheel,mousemove,pointermove, touchmove)并延遲調(diào)度,直到下一個requestAnimationFrame執(zhí)行。

離散事件則立即執(zhí)行,如keydown,keyup,mouseup,mousedown,touchstart,touchend

用了十幾年的瀏覽器,你卻只會瀏覽

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

用了十幾年的瀏覽器,你卻只會瀏覽

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

7. 使用getCoalescedEvents得到幀內(nèi)事件

大多數(shù)Web應用程序,合并事件應足以提供良好的用戶體驗。構(gòu)建繪制應用程序并根據(jù)touchmove坐標放置路徑等可能會丟失中間坐標以繪制平滑線,可以使用getCoalescedEvents指針事件中的方法來獲取這些合并事件的信息。

用了十幾年的瀏覽器,你卻只會瀏覽

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

window.addEventListener('pointermove', event = > { const events = event.getCoalescedEvents(); for (let event of events) { const x = event.pageX; const y = event.pageY; // draw a line using x and y coordinates. }});

六、小結(jié)

瀏覽器是一個復雜的系統(tǒng),這里介紹的只是冰山一角,chromium項目也在不停地迭代更新,所以可能一段時間后,某些功能已經(jīng)發(fā)生了變化。更加細節(jié)及最新的可以關(guān)注一下最新的chromium源碼。

參考文獻

1、Inside look at modern web browser:https://developers.google.com/web/updates/2018/09/inside-browser-part1

2、V8:https://v

3、JavaScript module:https://v/features/modules

4、Gpu-accelerated-compositing:https://www./developers/design-documents/gpu-accelerated-compositing-in-chrome

5、Chrominum-design-documents:https://www./developers/design-documents

6、How Blink works:https://docs.google.com/document/d/1aitSOucL0VHZa9Z2vbRJSyAIsAz24kX8LFByQ5xQnUg/edit

7、Life of a Pixel 2018:https://docs.google.com/presentation/d/1boPxbgNrTU0ddsc144rcXayGA_WF53k96imRH8Mp34Y/edit

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多