瀏覽器工作原理06 [#]渲染流程(下):HTML、CSS和JavaScript是如何變成頁面的

引用

瀏覽器工作原理與實踐

簡單回顧下上節前三個階段的主要內容:在HTML頁面內容被提交給渲染引擎之后,渲染引擎首先將HTML解析為瀏覽器可以理解的DOM;然后根據CSS樣式表,計算出DOM樹所有節點的樣式;接著又計算每個元素的幾何坐標位置,并將這些信息保存在布局樹中

一、分層

現在我們有了布局樹,而且每個元素的具體位置信息都計算出來了,那么接下來是不是就要開始著手繪制頁面了?

答案依然是否定的。

因為頁面中有很多復雜的效果,如一些復雜的3D變換、頁面滾動,或者使用z-indexing做z軸排序等,為了更加方便地實現這些效果,渲染引擎還需要為特定的節點生成專用的圖層,并生成一棵對應的圖層樹(LayerTree)。如果你熟悉PS,相信你會很容易理解圖層的概念,正是這些圖層疊加在一起構成了最終的頁面圖像。

要想直觀地理解什么是圖層,你可以打開Chrome的“開發者工具”,選擇“Layers”標簽,就可以可視化頁面的分層情況,如下圖所示

從上圖可以看出,渲染引擎給頁面分了很多圖層,這些圖層按照一定順序疊加在一起,就形成了最終的頁面,你可以參考下圖

現在你知道了瀏覽器的頁面實際上被分成了很多圖層,這些圖層疊加后合成了最終的頁面。下面我們再來看看這些圖層和布局樹節點之間的關系,如文中圖所示:

通常情況下,并不是布局樹的每個節點都包含一個圖層,如果一個節點沒有對應的層,那么這個節點就從屬于父節點的圖層。如上圖中的span標簽沒有專屬圖層,那么它們就從屬于它們的父節點圖層。但不管怎樣,最終每一個節點都會直接或者間接地從屬于一個層。

那么需要滿足什么條件,渲染引擎才會為特定的節點創建新的層呢?通常滿足下面兩點中任意一點的元素就可以被提升為單獨的一個圖層。

第一點,擁有層疊上下文屬性的元素會被提升為單獨的一層。

頁面是個二維平面,但是層疊上下文能夠讓HTML元素具有三維概念,這些HTML元素按照自身屬性的優先級分布在垂直于這個二維平面的z軸上。你可以結合下圖來直觀感受下:

從圖中可以看出,明確定位屬性的元素、定義透明屬性的元素、使用CSS濾鏡的元素等,都擁有層疊上下文屬性。

第二點,需要剪裁(clip)的地方也會被創建為圖層。

不過首先你需要了解什么是剪裁,結合下面的HTML代碼:

<style>div {width: 200;height: 200;overflow:auto;background: gray;} 
</style>
<body><div ><p>所以元素有了層疊上下文的屬性或者需要被剪裁,那么就會被提升成為單獨一層,你可以參看下圖:</p><p>從上圖我們可以看到,document層上有A和B層,而B層之上又有兩個圖層。這些圖層組織在一起也是一顆樹狀結構。</p><p>圖層樹是基于布局樹來創建的,為了找出哪些元素需要在哪些層中,渲染引擎會遍歷布局樹來創建層樹(Update LayerTree)。</p> </div>
</body>

在這里我們把div的大小限定為200 * 200像素,而div里面的文字內容比較多,文字所顯示的區域肯定會超出200 * 200的面積,這時候就產生了剪裁,渲染引擎會把裁剪文字內容的一部分用于顯示在div區域,下圖是運行時的執行結果

出現這種裁剪情況的時候,渲染引擎會為文字部分單獨創建一個層,如果出現滾動條,滾動條也會被提升為單獨的層。你可以參考下圖:

所以說,元素有了層疊上下文的屬性或者需要被剪裁,滿足這任意一點,就會被提升成為單獨一層。

二、 圖層繪制

在完成圖層樹的構建之后,渲染引擎會對圖層樹中的每個圖層進行繪制,那么接下來我們看看渲染引擎是怎么實現圖層繪制的?

試想一下,如果給你一張紙,讓你先把紙的背景涂成藍色,然后在中間位置畫一個紅色的圓,最后再在圓上畫個綠色三角形。你會怎么操作呢?

通常,你會把你的繪制操作分解為三步

  • 制藍色背景;
  • 在中間繪制一個紅色的圓;
  • 再在圓上繪制綠色三角形

渲染引擎實現圖層的繪制與之類似,會把一個圖層的繪制拆分成很多小的繪制指令,然后再把這些指令按照順序組成一個待繪制列表,如下圖所示:

從圖中可以看出,繪制列表中的指令其實非常簡單,就是讓其執行一個簡單的繪制操作,比如繪制粉色矩形或者黑色的線等。而繪制一個元素通常需要好幾條繪制指令,因為每個元素的背景、前景、邊框都需要單獨的指令去繪制。所以在圖層繪制階段,輸出的內容就是這些待繪制列表。

你也可以打開“開發者工具”的“Layers”標簽,選擇“document”層,來實際體驗下繪制列表,如下圖所示:

在該圖中,區域1就是document的繪制列表,拖動區域2中的進度條可以重現列表的繪制過程。

# 柵格化(raster)操作

繪制列表只是用來記錄繪制順序和繪制指令的列表,而實際上繪制操作是由渲染引擎中的合成線程來完成的。你可以結合下圖來看下渲染主線程和合成線程之間的關系:

如上圖所示,當圖層的繪制列表準備好之后,主線程會把該繪制列表提交(commit)給合成線程,那么接下來合成線程是怎么工作的呢?

那我們得先來看看什么是視口,你可以參看下圖:

通常一個頁面可能很大,但是用戶只能看到其中的一部分,我們把用戶可以看到的這個部分叫做視口(viewport)。

在有些情況下,有的圖層可以很大,比如有的頁面你使用滾動條要滾動好久才能滾動到底部,但是通過視口,用戶只能看到頁面的很小一部分,所以在這種情況下,要繪制出所有圖層內容的話,就會產生太大的開銷,而且也沒有必要。

基于這個原因,合成線程會將圖層劃分為圖塊(tile),這些圖塊的大小通常是256x256或者512x512,如下圖所示:

然后合成線程會按照視口附近的圖塊來優先生成位圖,實際生成位圖的操作是由柵格化來執行的。所謂柵格化,是指將圖塊轉換為位圖。而圖塊是柵格化執行的最小單位。渲染進程維護了一個柵格化的線程池,所有的圖塊柵格化都是在線程池內執行的,運行方式如下圖所示:

通常,柵格化過程都會使用GPU來加速生成,使用GPU生成位圖的過程叫快速柵格化,或者GPU柵格化,生成的位圖被保存在GPU內存中。

相信你還記得,GPU操作是運行在GPU進程中,如果柵格化操作使用了GPU,那么最終生成位圖的操作是在GPU中完成的,這就涉及到了跨進程操作。具體形式你可以參考下圖:

從圖中可以看出,渲染進程把生成圖塊的指令發送給GPU,然后在GPU中執行生成圖塊的位圖,并保存在GPU的內存中。

三、合成和顯示

一旦所有圖塊都被光柵化,合成線程就會生成一個繪制圖塊的命令——“DrawQuad”,然后將該命令提交給瀏覽器進程。

瀏覽器進程里面有一個叫viz的組件,用來接收合成線程發過來的DrawQuad命令,然后根據DrawQuad命令,將其頁面內容繪制到內存中,最后再將內存顯示在屏幕上。

到這里,經過這一系列的階段,編寫好的HTML、CSS、JavaScript等文件,經過瀏覽器就會顯示出漂亮的頁面了。

四、渲染流水線大總結

好了,我們現在已經分析完了整個渲染流程,從HTML到DOM、樣式計算、布局、圖層、繪制、光柵化、合成和顯示。下面我用一張圖來總結下這整個渲染流程:

結合上圖,一個完整的渲染流程大致可總結為如下

  • 渲染進程將HTML內容轉換為能夠讀懂的DOM樹結構。
  • 渲染引擎將CSS樣式表轉化為瀏覽器可以理解的styleSheets,計算出DOM節點的樣式。
  • 創建布局樹,并計算元素的布局信息。
  • 對布局樹進行分層,并生成分層樹。
  • 為每個圖層生成繪制列表,并將其提交到合成線程。
  • 合成線程將圖層分成圖塊,并在光柵化線程池中將圖塊轉換成位圖。
  • 合成線程發送繪制圖塊命令DrawQuad給瀏覽器進程。
  • 瀏覽器進程根據DrawQuad消息生成頁面,并顯示到顯示器上

# 相關概念

有了上面介紹渲染流水線的基礎,我們再來看看三個和渲染流水線相關的概念——“重排”“重繪”和“合成”。理解了這三個概念對于你后續Web的性能優化會有很大幫助。

# 1. 更新了元素的幾何屬性(重排)

從上圖可以看出,如果你通過JavaScript或者CSS修改元素的幾何位置屬性,例如改變元素的寬度、高度等,那么瀏覽器會觸發重新布局,解析之后的一系列子階段,這個過程就叫重排。無疑,重排需要更新完整的渲染流水線,所以開銷也是最大的

# 2. 更新元素的繪制屬性(重繪)

接下來,我們再來看看重繪,比如通過JavaScript更改某些元素的背景顏色,渲染流水線會怎樣調整呢?你可以參考下圖:

從圖中可以看出,如果修改了元素的背景顏色,那么布局階段將不會被執行,因為并沒有引起幾何位置的變換,所以就直接進入了繪制階段,然后執行之后的一系列子階段,這個過程就叫重繪。相較于重排操作,重繪省去了布局和分層階段,所以執行效率會比重排操作要高一些

# 3. 直接合成階段

那如果你更改一個既不要布局也不要繪制的屬性,會發生什么變化呢?渲染引擎將跳過布局和繪制,只執行后續的合成操作,我們把這個過程叫做合成。具體流程參考下圖

在上圖中,我們使用了CSS的transform來實現動畫效果,這可以避開重排和重繪階段,直接在非主線程上執行合成動畫操作。這樣的效率是最高的,因為是在非主線程上合成,并沒有占用主線程的資源,另外也避開了布局和繪制兩個子階段,所以相對于重繪和重排,合成能大大提升繪制效率。

至于如何用這些概念去優化頁面,我們會在后面相關章節做詳細講解的,這里你只需要先結合“渲染流水線”弄明白這三個概念及原理就行

五、總結

Chrome的渲染流水線還是相當復雜晦澀,且難以理解,不過Chrome團隊在不斷添加新功能的同時,也在不斷地重構一些子階段,目的就是讓整體渲染架構變得更加簡單和高效,正所謂大道至簡。

六、思考時間

在優化Web性能的方法中,減少重繪、重排是一種很好的優化方式,那么結合文中的分析,你能總結出來為什么減少重繪、重排能優化Web性能嗎?那又有那些具體的實踐方法能減少重繪、重排呢?

  • 觸發repaint reflow的操作盡量放在一起,比如改變dom高度和設置margin分開寫,可能會出發兩次重排
  • 通過虛擬dom層計算出操作總得差異,一起提交給瀏覽器。之前還用過createdocumentfragment來匯總append的dom,來減少觸發重排重繪次數。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/908423.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/908423.shtml
英文地址,請注明出處:http://en.pswp.cn/news/908423.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

AI書簽管理工具開發全記錄(十三):TUI基本框架搭建

文章目錄 AI書簽管理工具開發全記錄&#xff08;十三&#xff09;&#xff1a;TUI基本框架搭建前言 &#x1f4dd;1.TUI介紹 &#x1f50d;2. 框架選擇 ??3. 功能梳理 &#x1f3af;4. 基礎框架搭建??4.1 安裝4.2 參數設計4.3 繪制ui4.3.1 設計結構體4.3.2 創建頭部4.3.3 創…

CC7利用鏈深度解析

CommonsCollections7&#xff08;CC7&#xff09;是CC反序列化利用鏈中的重要成員&#xff0c;由Matthias Kaiser在2016年發現。本文將從底層原理到實戰利用&#xff0c;全面剖析這條獨特而強大的利用鏈。 一、CC7鏈技術定位 1.1 核心價值 無第三方依賴&#xff1a;僅需JDK原…

openvino使用教程

OpenVINO使用教程 本專欄內容支持平臺章節計劃 本專欄內容 OpenVINO 是一款開源工具包&#xff0c;用于在云端、本地和邊緣部署高性能 AI 解決方案。我們可以使用來自最熱門模型框架的生成式和傳統 AI 模型來開發應用程序。充分利用英特爾 硬件的潛力&#xff0c;使用openvino…

ESP8266(NodeMcu)+GPS模塊+TFT屏幕實現GPS碼表

前言 去年寫過一篇關于使用esp8266(nodemcu)gps模塊oled屏幕diy的gps定位器的文章.點擊回顧 .無奈OLED屏幕太小了,最近剛好有時間又折騰使用TFT屏幕diy了一款gps碼表 效果如圖 材料準備 依舊是請出我們的兩位老演員 nocdmcu一塊. GPS定位模塊(我買的大夏龍雀的DX-GP10-GP…

解決獲取視頻第一幀黑屏問題

文章目錄 解決獲取視頻第一幀黑屏問題核心代碼 解決獲取視頻第一幀黑屏問題 廢話不多說&#xff0c;直接上代碼&#xff1a; <script setup> const status ref(請點擊“添加視頻”按鈕添加視頻) const videoElement ref(document.createElement(video)) const curren…

通過BUG(prvIdleTask、pxTasksWaitingTerminatio不斷跳轉問題)了解空閑函數(prvIdleTask)和TCB

一、前言與問題 在基于 FreeRTOS 的嵌入式系統中&#xff0c;我使用 STM32F1 開發一個 MQTT 客戶端應用&#xff0c;涉及兩個主要任務&#xff1a; ATRecvParser&#xff1a;負責解析 Wi-Fi 模塊的 AT 命令響應&#xff08;如 OK、ERROR 和 IPD 數據&#xff09;。MQTT_Clien…

繼MySQL之后的技術-JDBC-從淺到深-02

目錄 概念 編程六部曲 SQL注入和statement 工具類的封裝 JDBC事務 模糊查詢 批處理 數據庫連接池 Apache-DBUtils BasicDao 概念 JDBC為訪問不同的數據庫提供了統一的接口&#xff0c;為使用者屏蔽了細節問題。 Java程序員使用JDBC&#xff0c;可以連接任何提供了JD…

【配置 YOLOX 用于按目錄分類的圖片數據集】

現在的圖標點選越來越多&#xff0c;如何一步解決&#xff0c;采用 YOLOX 目標檢測模式則可以輕松解決 要在 YOLOX 中使用按目錄分類的圖片數據集&#xff08;每個目錄代表一個類別&#xff0c;目錄下是該類別的所有圖片&#xff09;&#xff0c;你需要進行以下配置步驟&#x…

淺談python如何做接口自動化

工具與環境準備 開發工具 PyCharm專業版&#xff1a;支持項目視圖、代碼導航、調試功能和主流框架開發官方資源&#xff1a;JetBrains PyCharm 數據庫操作 使用mysqlclient庫操作MySQL&#xff08;Django官方推薦&#xff09;安裝命令&#xff1a;pip install mysqlclient1.3.…

知識圖譜技術概述

一、概述 知識圖譜&#xff08;Knowledge Graph&#xff09; 是一種基于圖結構的語義網絡&#xff0c;用于表示實體及其之間的關系&#xff0c;旨在實現更智能的知識表示和推理。它通過將現實世界中的各類信息抽象為 “實體-關系-實體” 的三元組結構&#xff0c;構建出復雜的知…

NodeJS Koa 后端用戶會話管理,JWT, Session,長短Token,本文一次性講明白

前言 前幾天&#xff0c;我寫了一篇文章&#xff0c;《我設計的一個安全的 web 系統用戶密碼管理流程》。其中著重點是講的如何利用非對稱加密進行安全的設計&#xff0c;并在講述了原理之后&#xff0c;又寫了 《node 后端和瀏覽器前端&#xff0c;有關 RSA 非對稱加密的完整…

0.5S 級精度背后:DJSF1352-RN-6 如何讓儲能電站的每 1kWh 都「有跡可循」?

1、背景 在能源轉型的時代洪流里&#xff0c;大型儲能電站作為保障電網穩定運行、平衡能源供需的核心基礎設施&#xff0c;其戰略價值愈發凸顯。而儲能電站的高效運轉&#xff0c;始終離不開精準的電能計量體系支撐。今日為您重點推介一款針對 1500V 儲能系統研發的專業電能表…

Linux運維筆記:服務器安全加固

文章目錄 背景加固措施1. 修改用戶密碼2. 使用公鑰認證替代密碼登錄3. 強化系統安全4. 掃描與清理殘留威脅5. 規范軟件管理&#xff08;重點&#xff09; 注意事項總結 提示&#xff1a;本文總結了大學實驗室 Linux 電腦感染挖礦病毒后的安全加固措施&#xff0c;重點介紹用戶密…

Pycharm 配置解釋器

今天更新了一版pycharm&#xff0c;因為很久沒有配置解釋器了&#xff0c;發現一直失敗。經過來回試了幾次終于成功了&#xff0c;記錄一下過程。 Step 1 Step 2 這里第二步一定要注意類型要選擇python 而不是conda。 雖然我的解釋器是conda 里面建立的一個環境。挺有意思的

【Linux】awk 命令詳解及使用示例:結構化文本數據處理工具

【Linux】awk 命令詳解及使用示例&#xff1a;結構化文本數據處理工具 引言 awk 是一種強大的文本處理工具和編程語言&#xff0c;專為處理結構化文本數據而設計。它的名稱來源于其三位創始人的姓氏首字母&#xff1a;Alfred Aho、Peter Weinberger 和 Brian Kernighan。 基…

MS1023/MS1224——10MHz 到 80MHz、10:1 LVDS 并串轉換器(串化器)/串并轉換器(解串器)

產品簡述 MS1023 串化器和 MS1224 解串器是一對 10bit 并串 / 串并轉 換芯片&#xff0c;用于在 LVDS 差分底板上傳輸和接收 10MHz 至 80MHz 的并行字速率的串行數據。起始 / 停止位加載后&#xff0c;轉換為負載編 碼輸出&#xff0c;串行數據速率介于 120Mbps…

跟我學c++中級篇——理解類型推導和C++不同版本的支持

一、類型推導 在前面反復分析過類型推導&#xff08;包括前面提到的類模板參數推導CTAD&#xff09;&#xff0c;類型推導其實就是滿足C語言這種強類型語言的要求即編譯期必須確定對象的數據類型。換一句話說&#xff0c;理論上如果編譯器中能夠自動推導所有的相關數據類型&am…

vue3+TS+eslint9配置

記錄eslint升級到9.x的版本之后遇到的坑 在 ESLint 9 中&#xff0c;配置方式發生了變化。Flat Config 格式&#xff08;eslint.config.js 或 .ts&#xff09;不再支持 extensions 選項。所以vscode編輯器中的 extensions 需要注釋掉&#xff0c;要不然保存的時候不會格式化。…

書籍推薦 --- 《篳路維艱:中國經濟社會主義路徑的五次選擇》

蕭冬連.篳路維艱:中國社會主義路徑的五次選擇[M]. 前不久看完的這本書&#xff0c;還是蠻受震撼的。 這本書比較細致地(引用了很多的史料)、從中央高層的視角講解了從新中國成立一直到改革開放初期這30多年里(1949---1980年代)發生在我國的幾次重大事件(三大改造、第一個五年計…

C++課設:簡易日歷程序(支持傳統節假日 + 二十四節氣 + 個人紀念日管理)

名人說&#xff1a;路漫漫其修遠兮&#xff0c;吾將上下而求索。—— 屈原《離騷》 創作者&#xff1a;Code_流蘇(CSDN)&#xff08;一個喜歡古詩詞和編程的Coder&#x1f60a;&#xff09; 專欄介紹&#xff1a;《編程項目實戰》 目錄 一、為什么要開發一個日歷程序&#xff…