日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

浏览器渲染原理的学习与总结

發(fā)布時間:2024/1/1 HTML 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 浏览器渲染原理的学习与总结 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

參考文章:瀏覽器渲染原理

瀏覽器渲染原理

1. 進程和線程

進程包涵線程,

微信是一個進程, 里面有很多諸如用戶登錄等線程.

a.線程共享內(nèi)存, 進程獨立內(nèi)存:

進程與進程之間是相互獨立的, 他們各自有各自的內(nèi)存, 而線程之間是獨立的, 但他們共享同一個內(nèi)存空間.

b.線程依賴進程, 進程控制線程

沒有進程, 線程就不存在, 需要進程來控制多個線程的執(zhí)行.

c.「為了提升瀏覽器的穩(wěn)定性和安全性,瀏覽器采取了多進程模型。」

如果一個頁面有問題,不影響其他頁面的運行。

2.瀏覽器進程架構(gòu)

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-9583XeF9-1644134091925)(星期五.assets/image-20220204161822885.png)]

  • 「瀏覽器進程。**「主要負責」**界面顯示」「用戶交互」「子進程管理」、同時提供**「存儲」**等功能。
  • 「渲染進程。」 核心任務(wù)是將HTML、CSS和JavaScript轉(zhuǎn)換為**「用戶可以與之交互的網(wǎng)頁」,排版引擎Blink和JavaScript引擎V8都運行在該進程中,默認情況下,Chrome為每一個Tab標簽頁創(chuàng)建一個渲染進程。出于安全考慮,渲染進程都是運行在「沙箱模式」**下的。
  • **GPU進程。**GPU圖形處理器(英語:graphics processing unit,縮寫:GPU),負責3D CSS效果,網(wǎng)頁,Chrome ui的繪制。
  • 「網(wǎng)絡(luò)進程」。主要負責頁面的**「網(wǎng)絡(luò)資源加載」**,之前是作為一個模塊運行在瀏覽器進程里面的,直至最近才獨立處理,成為單獨一個進程。
  • 「插件進程」。主要負責**「插件的運行」**,因為插件易崩潰,所以通過插件進程來隔離,以保證插件進程崩潰不會對瀏覽器和頁面造成影響。每一種類型的插件對應(yīng)一個進程,僅當使用該插件時才創(chuàng)建。

所以我們開啟一個頁面,至少會啟動4個進程。

3.瀏覽器的 Http 請求進程

3.1 工作步驟

  • 構(gòu)造請求

    首先,瀏覽器構(gòu)造請求行,構(gòu)建好之后,瀏覽器準備發(fā)起網(wǎng)絡(luò)請求

  • 查找緩存

    在發(fā)起請求前, 還要確認一下是否有緩存, 如果本來就有這個請求的緩存的話, 瀏覽器會攔截請求返回該資源的副本,并直接結(jié)束請求

    這樣可以**「緩解服務(wù)的壓力,提升性能」**。如果緩存查找失敗,則進入網(wǎng)絡(luò)請求。

  • 準備IP地址和端口

    瀏覽器使用 HTTP 協(xié)議在應(yīng)用層上封裝請求的文本信息, 之后用 TCP/IP 協(xié)議作傳輸層協(xié)議傳到網(wǎng)絡(luò)上,

    正因如此, 在 HTTP 開始工作前, 瀏覽器先要與服務(wù)器建立 TCP/IP 連接。也就是說HTTP的內(nèi)容是通過TCP的傳輸數(shù)據(jù)階段來實現(xiàn)的。

    [外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-RcUe3ryv-1644134091926)(星期五.assets/image-20220204162913595.png)]

    數(shù)據(jù)包是通過 IP 地址傳輸給接收方的, 但是 IP 地址太難記了, 用域名來記更方便, 就出現(xiàn)了 DNS (域名系統(tǒng)) , 來為 ’ IP 地址 ’’ 域名地址 ’ 做一次映射.

    第一步瀏覽器會請求 DNS 返回域名對應(yīng)的 IP。「當然瀏覽器還提供了 DNS 數(shù)據(jù)緩存服務(wù)」.

  • 「等待TCP隊列」

  • ? 準備好 IP 和端口之后, 瀏覽器還有個檢查機制, 因為瀏覽器規(guī)定一個域名的TCP鏈接不能超過六個, 如果少于六個, 就進入下一步, 建立tcp鏈接

  • 「建立TCP連接」
  • 排隊等待結(jié)束后,建立TCP連接

  • 「發(fā)送HTTP請求」
  • ?

    通常情況下,一旦服務(wù)器向客戶端返回了請求數(shù)據(jù),它就要關(guān)閉TCP連接Connection:Keep-Alive之后講, 有了這個, 就不需要重復(fù)建立新的TCP連接。瀏覽器可以繼續(xù)通過同一個TCP連接發(fā)送請求。不會關(guān)閉TCP鏈接

    3.2 為什么網(wǎng)站第二次打開這么快

    因為DNS和頁面資源被緩存了: 「DNS緩存」「頁面資源緩存」

    瀏覽器通過響應(yīng)頭的Cache-Control字段來設(shè)置是否緩存該資源。

    Cache-Control:Max-age=2000 //緩存過期時間是2000

    但如果緩存過期了,瀏覽器則會繼續(xù)發(fā)送網(wǎng)絡(luò)請求,并且在HTTP請求頭中帶上:

    If-None-Match:"4f80f-13c-3a1xb12a"

    簡要來說,很多網(wǎng)站第二次訪問能夠秒開,是因為瀏覽器緩存直接使用本地副本來回應(yīng)請求,而不會產(chǎn)生真實的網(wǎng)絡(luò)請求,DNS 數(shù)據(jù)也被瀏覽器緩存了,這又省去了 DNS 查詢環(huán)節(jié)

    4.輸入url到瀏覽器顯示頁面發(fā)生了啥

    名詞解釋:

    **重定向:**重定向的意思就是說瀏覽器里面指定訪問的一個url地址,去網(wǎng)站服務(wù)器里面訪問后,
    網(wǎng)站的服務(wù)器又指向瀏覽器中另外的一個地址,然后瀏覽器再去訪問網(wǎng)站服務(wù)器的那個另外的地址。

    提交文檔:所謂提交文檔,就是「瀏覽器主進程」「將網(wǎng)絡(luò)進程接收到的HTML數(shù)據(jù)提交給渲染進程」

    [外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2hxQpJqi-1644134091927)(星期五.assets/image-20220206141216703.png)]

    1、**「瀏覽器進程」接收到用戶輸入的URL請求,「瀏覽器進程」**便將URL轉(zhuǎn)發(fā)給網(wǎng)絡(luò)進程。

    2、**「網(wǎng)絡(luò)進程」**中發(fā)起真正的URL請求。

    3、「網(wǎng)絡(luò)進程」接收到響應(yīng)頭數(shù)據(jù),便解析響應(yīng)頭數(shù)據(jù),并將數(shù)據(jù)轉(zhuǎn)發(fā)給「瀏覽器進程」

    4、「瀏覽器進程」接收到網(wǎng)絡(luò)進程的響應(yīng)頭數(shù)據(jù)之后,發(fā)送"「提交文檔」"消息到**「渲染進程」**。

    5、「渲染進程」接收到"提交文檔"的消息之后,便開始準備接收HTML數(shù)據(jù),接收數(shù)據(jù)的方式是直接和「網(wǎng)絡(luò)進程」建立「數(shù)據(jù)管道。」

    6、等文檔數(shù)據(jù)傳輸完成之后,「渲染進程」會返回“確認提交”的消息給「瀏覽器進程」

    7、「瀏覽器進程」接收到「渲染進程」"確認提交"的消息之后,便開始移除之前舊的文檔,然后更新**「瀏覽器進程」**中的頁面狀態(tài)。

    5.瀏覽器的渲染流程

    HTML,DOM,樣式計算,布局,圖層,繪制,柵格化,合成和顯示。

    一個完整的渲染流程大致可總結(jié)如下:

  • 渲染進程將HTML內(nèi)容轉(zhuǎn)換為瀏覽器能夠讀懂的**「DOM樹」**結(jié)構(gòu)。

  • 渲染引擎將CSS樣式表轉(zhuǎn)化為瀏覽器能夠理解的**「CSS樹」**,計算出DOM節(jié)點的樣式。分三步

  • 將css文本轉(zhuǎn)換為瀏覽器能理解的樣式表

  • 標準化樣式表中的屬性值(比如bule變成rgb值之類的)

  • 根據(jù)CSS的**「繼承規(guī)則」「層疊規(guī)則」**計算每個dom節(jié)點的樣式

    ? 繼承規(guī)則就是繼承祖先節(jié)點的文本和字體樣式之類的,比如body { font-size: 20px }

    ? 層疊規(guī)則就是計算樣式權(quán)重

  • DOM樹 + CSS樹創(chuàng)建布局樹,并計算元素的布局信息。

    所有不可見的節(jié)點都沒有包含到布局樹中。

    計算布局樹節(jié)點的坐標位置。即計算元素在視口上確切的位置和大小。

  • 對布局樹進行分層,并生成**「圖層樹」**。

    因為頁面中有很多復(fù)雜的效果,如一些**「復(fù)雜的3D轉(zhuǎn)換」「頁面滾動」**,或者使用z-index,為了更方便的實現(xiàn)這些效果,「渲染引擎還需要為特定的節(jié)點生成專門的圖層,并生成一棵對應(yīng)的圖層樹(LayerTree)」。

    不是所有節(jié)點都會有圖層,這時候看滿不滿足兩個要求

  • 對每個**「圖層」生成「繪制列表」**,并將其提交給合成線程。

    渲染引擎把一個圖層的繪制拆分為很多小的繪制指令,然后再把這些指令按照順序組成一個待繪制列表并提交給合成線程

  • 對每個圖層進行單獨的繪制

    合并線程的主場:根據(jù)視圖劃分圖層為圖塊,按照視口附近的圖塊來優(yōu)先生成位圖,也就是優(yōu)先GPU柵格化,并保存在GPU中

  • 合并圖層。

    一旦所有圖塊被柵格化,合成線程就會生成一個繪制圖塊的命令—“DrawQuad”,然后將該命令提交給瀏覽器進程。瀏覽器進程里的viz組件接收該指令并將頁面內(nèi)容繪制在內(nèi)存中,最后顯示在屏幕上

  • 接下來我們從一個簡單的html頁面來談瀏覽器的渲染流程:

    5.1 構(gòu)建 DOM 樹

    HTML內(nèi)容轉(zhuǎn)換為瀏覽器DOM樹結(jié)構(gòu)的過程:字節(jié) → 字符 → 令牌 → 節(jié)點 → 對象模型。

    • 轉(zhuǎn)換: 瀏覽器從磁盤或網(wǎng)絡(luò)讀取 HTML 的原始字節(jié),并根據(jù)文件的指定編碼(例如 UTF-8)將它們轉(zhuǎn)換成各個字符。
    • 令牌化: 瀏覽器將字符串轉(zhuǎn)換成 W3C HTML5 標準規(guī)定的各種令牌,例如,“”、“”,以及其他尖括號內(nèi)的字符串。每個令牌都具有特殊含義和一組規(guī)則。
    • 詞法分析: 發(fā)出的令牌轉(zhuǎn)換成定義其屬性和規(guī)則的“對象”。
    • DOM 構(gòu)建: 最后,由于 HTML 標記定義不同標記之間的關(guān)系(一些標記包含在其他標記內(nèi)),創(chuàng)建的對象鏈接在一個樹數(shù)據(jù)結(jié)構(gòu)內(nèi),此結(jié)構(gòu)也會捕獲原始標記中定義的父項-子項關(guān)系: HTML 對象是 body 對象的父項,body 是 paragraph 對象的父項,依此類推。

    當解析器發(fā)現(xiàn)非阻塞資源,例如一張圖片,瀏覽器會請求這些資源并且繼續(xù)解析。當遇到一個CSS文件時,解析也可以繼續(xù)進行,但是對于<script>標簽(特別是沒有 async 或者 defer 屬性)會阻塞渲染并停止HTML的解析。

    瀏覽器構(gòu)建DOM樹時,這個過程占用了主線程。當這種情況發(fā)生時,**「預(yù)加載掃描儀」**將解析可用的內(nèi)容并請求高優(yōu)先級資源,如CSS、JavaScript和web字體。多虧了預(yù)加載掃描器,我們不必等到解析器找到對外部資源的引用來請求它。它將在后臺檢索資源,以便在主HTML解析器到達請求的資源時,它們可能已經(jīng)在運行,或者已經(jīng)被下載。預(yù)加載掃描儀提供的優(yōu)化減少了阻塞。

    5.2 樣式計算

    樣式計算的目的是為了計算出DOM節(jié)點中每一個元素的具體樣式,這個階段大體分三步。

  • 將css文本轉(zhuǎn)換為瀏覽器能理解的樣式表

  • 標準化樣式表中的屬性值(比如bule變成rgb值之類的)

  • 根據(jù)CSS的**「繼承規(guī)則」「層疊規(guī)則」**計算每個dom節(jié)點的樣式

    繼承規(guī)則就是繼承祖先節(jié)點的文本和字體樣式之類的,比如body { font-size: 20px }

    層疊規(guī)則就是計算樣式權(quán)重

  • 5.2.1 把CSS轉(zhuǎn)換為瀏覽器內(nèi)容理解的結(jié)構(gòu):將css文本轉(zhuǎn)換為樣式表

    CSS來源有:

    • 外部樣式表:通過link引用的CSS文件
    • 內(nèi)部樣式表:style標簽內(nèi)的CSS
    • 內(nèi)聯(lián)樣式:元素的style屬性內(nèi)嵌的CSS

    和HTML文件一樣,瀏覽器也是無法直接理解這些純文本的CSS樣式,所以**「當渲染引擎接收到CSS文本的時,會執(zhí)行一個轉(zhuǎn)換操作,將css文本轉(zhuǎn)換為瀏覽器可以理解的結(jié)構(gòu)—styleSheets。」**

    渲染引擎會把獲取到的 CSS 文本全部轉(zhuǎn)換為 styleSheets 結(jié)構(gòu)中的數(shù)據(jù),并且該結(jié)構(gòu)同時具備了查詢和修改功能,這會為后面使用JS的樣式操作提供基礎(chǔ)。

    5.2.2 轉(zhuǎn)換樣式表中的屬性值,使其標準化

    我們已經(jīng)將CSS轉(zhuǎn)換為瀏覽器能理解的結(jié)構(gòu)了,那么接下來就要對其進行屬性值的標準化操作。

    body { font-size: 2em } p {color:blue;} span {display: none} div {font-weight: bold} div p {color:green;} div {color:red; }

    所以需要將所有值如 2em、blue、bold,轉(zhuǎn)換為渲染引擎容易理解的、標準化的計算值,這個過程就是屬性值標準化。

    5.2.3 計算出DOM樹中每一個節(jié)點的具體樣式

    這里就涉及到CSS的**「繼承規(guī)則」「層疊規(guī)則」**了。

    樣式計算階段的目的是為了計算出 DOM 節(jié)點中每個元素的具體樣式,在計算過程中需要遵守 CSS 的繼承和層疊兩個規(guī)則。這個階段最終輸出的內(nèi)容是每個 DOM 節(jié)點的樣式,并被保存在 ComputedStyle 的結(jié)構(gòu)內(nèi)。

    每個 DOM 元素最終的計算樣式,可以打開 Chrome 的“開發(fā)者工具”,選擇第一個“element”標簽,然后再選擇“Computed”子標簽

    5.3 布局階段

    現(xiàn)在,我們有DOM樹和DOM樹中元素的樣式,但是還足以顯示頁面,因為我們還不知道DOM元素的幾何位置,那么接下來就需要**「計算出DOM樹中可見元素的幾何位置,我們把這個計算過程叫做布局」**。

    Chrome在布局階段需要完成兩個任務(wù):

  • 創(chuàng)建布局樹
  • 布局計算
  • 5.3.1 創(chuàng)建布局樹

    DOM樹有些元素不會在頁面上顯示,被用戶看到,如head標簽和使用了display:none的元素。所以在顯示之前,我么還要額外地構(gòu)建一棵**「只包含了可見元素的布局樹」**。

    從上圖可以看出,DOM樹中所有不可見的節(jié)點都沒有有包含到布局樹中

    5.3.2 布局計算

    我們已經(jīng)有了一棵完整的布局樹,那么接下來就要根據(jù)DOM節(jié)點對應(yīng)的CSS樹中的樣式,計算布局樹節(jié)點的坐標位置。即計算元素在視口上確切的位置和大小。

    5.4 分層 (圖層樹)

    有了布局樹之后,每個元素的具體位置信息都計算出來了,那么接下來是不是就要開始著手繪制頁面了?不是。因為頁面中有很多復(fù)雜的效果,如一些**「復(fù)雜的3D轉(zhuǎn)換」「頁面滾動」,或者使用z-index,為了更方便的實現(xiàn)這些效果,「渲染引擎還需要為特定的節(jié)點生成專門的圖層,并生成一棵對應(yīng)的圖層樹(LayerTree)」**。這和PS的圖層類似,正是這些圖層疊加在一起才最終構(gòu)成了頁面圖像。

    想要直觀的理解什么是圖層,可以打開Chrome的"開發(fā)工具",選擇Layers標簽,就可以查看可視化頁面的分層情況。

    「布局樹和圖層樹的關(guān)系」

    通常情況下,并不是布局樹中的每一個節(jié)點都包含一個圖層,如果一個節(jié)點沒有對應(yīng)的圖層,那么這個節(jié)點就從屬于父節(jié)點的圖層。那么什么情況滿足,渲染引擎才會為特定的節(jié)點創(chuàng)建新的圖層呢?滿足一下兩個條件中的任意一個,元素就可以被單獨提升為一個圖層。

  • 「擁有層疊上下文屬性的元素會被提升為單獨的一層」
  • 頁面是一個二維平面,但層疊上下文能夠上HTML元素擁有三維概念,這些HTML元素按自身屬性的優(yōu)先級分布在垂直于這個二維平面的Z軸上,以下情況會作為單獨的圖層。

    • position:fixed
    • css 3d 例如:transform:rotateX(30deg)
    • video
    • canvas
    • 有CSS3動畫的節(jié)點
    • will-change
  • 「需要剪裁的地方也會被創(chuàng)建為圖層」
  • 那么什么是剪裁,結(jié)合以下代碼

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>div {width: 200px;height: 200px;overflow:auto;background: gray;} </style> </head> <body><div ><p>所以元素有了層疊上下文的屬性或者需要被剪裁,那么就會被提升成為單獨一層,你可以參看下圖:</p><p>從上圖我們可以看到,document層上有A和B層,而B層之上又有兩個圖層。這些圖層組織在一起也是一顆樹狀結(jié)構(gòu)。</p><p>圖層樹是基于布局樹來創(chuàng)建的,為了找出哪些元素需要在哪些層中,渲染引擎會遍歷布局樹來創(chuàng)建層樹(Update LayerTree)。</p> </div> </body> </html>

    這里我么把div的大小限定為200 * 200像素,而div里面的文字內(nèi)容比較多,文字所顯示的區(qū)域肯定會超過200 * 200的面積,這時候就產(chǎn)生了剪裁,渲染引擎會把裁剪文字內(nèi)容的一部分用于顯示在div區(qū)域,下面是運行時的執(zhí)行結(jié)果:

    出現(xiàn)這種裁剪情況時,渲染引擎會為文字單獨為文字創(chuàng)建一層,如出現(xiàn)滾動條,滾動條也會被提升為單獨的層。

    5.5 圖層的繪制

    在完成圖層樹的構(gòu)建之后,渲染引擎會對圖層樹中的每個圖層進行繪制,那么接下來我們看看渲染引擎是如何實現(xiàn)圖層的繪制?

    如果給你一張紙,讓你先把背景涂成暗色,然后再中間中間位置花一個紅色的圓,最后在圓上畫一個綠色三角,你會怎么操作,通常你會按順序操作。

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

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

    5.6 柵格化操作

    柵格化,就是指將圖塊轉(zhuǎn)化為位圖。

    合成線程接收到上面的繪制列表后的工作:因為視口,合成線程會把圖層劃分多個圖塊,然后每個圖塊按離視口的距離被優(yōu)先交由GPU柵格化生成位圖,并保存在GPU中

    繪制列表指令用來記錄繪制順序和繪制指令的列表,而實際上**「繪制操作是由渲染引擎中的合成線程來完成」**。結(jié)合下圖看渲染主線程和合成線程之間的關(guān)系:

    如上圖所示,當圖層的繪制列表準備好之后,主線程會把該繪制列表提交給合成線程,那么合成線程是如何工作的?

    首先我們談一個概念,「視口」。什么是視口?

    通常一個頁面可能很大,用戶只能看到其中的一部分,我們把**「用戶可以看到的這個區(qū)域叫視口(viewport)。」**

    比如說,一個圖層很大,頁面需要滾動底部,才能全部顯示。但是通過視口,用戶只能看到頁面很小的一部分,所以在此種情況下,要一次性繪制完圖層所有的內(nèi)容,會產(chǎn)生很大的開銷,且沒有必要。

    基于這個原因,「合成線程會將圖層劃分為圖塊」,這些圖塊的大小通常是256 * 256或512 * 512。然后**「合成線程會按照視口附近的圖塊來優(yōu)先生成位圖」**,實際生成位圖的操作就是有柵格化來執(zhí)行的。所謂柵格化,**是指將圖塊轉(zhuǎn)化為位圖(所謂位圖就是能夠看的到的圖層區(qū)域)。而圖塊是柵格化執(zhí)行的最小單位。**渲染進程維護了一個柵格化的線程池,所有的圖塊柵格化都是在線程池內(nèi)執(zhí)行,運行方式如下圖所示:

    通常,柵格化過程都會使用GPU來加速生成,「使用GPU生成位圖過程叫快速柵格化,或者GPU柵格化」,生成的位圖被保存在GPU內(nèi)存中。GPU操作是運行在GPU進程中的,那么柵格化,還涉及到了跨進程操作。

    從圖中可以看出,渲染進程把生成圖塊的指令發(fā)送給 GPU,然后在 GPU 中執(zhí)行生成圖塊的位圖,并保存在 GPU 的內(nèi)存中。

    5.7 合成和顯示

    一旦所有圖塊被柵格化,合成線程就會生成一個繪制圖塊的命令—“DrawQuad”,然后將該命令提交給瀏覽器進程。瀏覽器進程里的viz組件接收該指令并將頁面內(nèi)容繪制在內(nèi)存中,最后顯示在屏幕上

    到此,經(jīng)過一系列的階段,編寫好的HTML、CSS、JavaScript等文件,經(jīng)過瀏覽器就會顯示為頁面。

    6.重排、重繪、合成

    重排:幾何位置的改變,width等,也稱回流,需要更新完整的渲染流水線,開銷最大

    重繪:繪制屬性的改變,背景顏色等,省去了布局和分層階段

    合成:比如css的transition動畫,更改一個既不要布局也不要繪制的屬性,渲染引擎將跳過布局、分層和繪制,只執(zhí)行后續(xù)的合成操作,

    6.1 更新元素的幾何屬性(重排)

    從上圖可以看出,如果你**「通過JS或CSS修改元素的幾何位置屬性」,如width,height等,那么會觸發(fā)瀏覽器的重新布局,解析之后的一系列子階段,這個過程就叫重排也稱回流。「重排需要更新完整的渲染流水線,所以開銷也最大的。」

    6.2 更新元素的繪制屬性(重繪)

    比如通過JS更改某些元素的背景顏色,渲染流水的調(diào)整參見下圖:

    修改元素的背景色,布局階段不會執(zhí)行,因為**「沒有引起幾何位置的變換」,所以直接進入繪制,然后執(zhí)行之后的一系列子階段,這個過程就叫「重繪」。相較重排操作,「重繪省去了布局和分層階段,所以執(zhí)行效率會比重排效率高。」**

    6.3 直接合成階段

    那如果你更改一個既不要布局也不要繪制的屬性,渲染引擎將跳過布局和繪制,只執(zhí)行后續(xù)的合成操作,我們把這個過程叫做**「合成。」**

    在上圖,我們使用CSS的transform來實現(xiàn)動畫效果,可以避開重排和重繪階段,直接在非主線程上執(zhí)行合成動畫操作。這樣的效率最高,因為是在非主線程上合成的,并沒有占用主線程的資源。

    7.優(yōu)化

    如果我們要提升性能,需要做的就是減少瀏覽器的重繪和回流

    • CSS
  • 避免使用table布局。
  • 盡可能在DOM樹的最末端改變class。
  • 避免設(shè)置多層內(nèi)聯(lián)樣式。
  • 將動畫效果應(yīng)用到position屬性為absolute或fixed的元素上。
  • 避免使用CSS表達式(例如:calc())。
    • JS
  • 避免頻繁操作樣式,最好一次性重寫style屬性,或者將樣式列表定義為class并一次性更改class屬性。
  • 避免頻繁操作DOM,創(chuàng)建一個documentFragment,在它上面應(yīng)用所有DOM操作,最后再把它添加到文檔中。
  • 也可以先為元素設(shè)置display: none,操作結(jié)束后再把它顯示出來。因為在display屬性為none的元素上進行的DOM操作不會引發(fā)回流和重繪。
  • 避免頻繁讀取會引發(fā)回流/重繪的屬性,如果確實需要多次使用,就用一個變量緩存起來。
  • 對具有復(fù)雜動畫的元素使用絕對定位,使它脫離文檔流,否則會引起父元素及后續(xù)元素頻繁回流。
  • 總結(jié)

    以上是生活随笔為你收集整理的浏览器渲染原理的学习与总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。