浏览器从输入URL到页面渲染过程 ——页面渲染流程
之前我有總結過一篇經典面試題:瀏覽器從輸入URL到頁面渲染過程 ,接下里我將對某些知識點進行更細致的解析。
瀏覽器從輸入URL到頁面渲染過程 系列文章:
(一):瀏覽器從輸入URL到頁面渲染過程 —— 瀏覽器的進程與線程
————————————————————————————————————————————————————
瀏覽器從輸入URL到頁面渲染過程 ——頁面渲染流程
瀏覽器的渲染機制很復雜,從輸入HTML到頁面輸出大致分為以下這些步驟:
構建DOM樹 > 構建styleSheets樹 > 布局 > 分層 > 繪制 >分塊 > 光柵化 > 合成
構建DOM樹
-
為什么要構建 DOM 樹?
因為瀏覽器無法直接理解和使用 HTML,所以需要將 HTML 轉換為瀏覽器能夠理解的結構——DOM 樹。
什么是樹結構:節點與節點之間通過父子關系相連接。
具體流程如下:
我們在chrome的控制臺輸入:document ,便能看到此DOM樹結構:
雖然 DOM樹 和 HTML 看起來并沒有什么的區別,但是DOM樹在內存中是以樹狀結構存儲的,可以被JS代碼所查詢操作。例如:
樣式計算(構建styleSheets)
-
為什么要構建 styleSheets ?
和 HTML 文件一樣,瀏覽器也是無法直接理解這些純文本的 CSS 樣式,所以當渲染引擎接收到 CSS 文本時,會執行一個轉換操作,將 CSS 文本轉換為瀏覽器可以理解的結構——styleSheets。
-
什么是瀏覽器可以理解的style?
rem/em ————> px
color: blue ————> rgb(0, 0, 255)
font-weight: blod ————> 700
… -
CSS來源有哪些呢?
1、通過 link 引用的外部 CSS 文件
2、< style >標記內的 CSS
3、元素的 style 屬性內嵌的 CSS
如果這三個地方都有對同一標簽進行樣式定義,或者該標簽沒有被定義樣式,那它的最終樣式會是什么樣的呢?這時候,就需要進行樣式計算了。
樣式計算規則:繼承規則、層疊規則
繼承規則:當前標簽的樣式繼承了其所有父標簽的樣式。
層疊規則:多個樣式同時作用于該標簽時,進行樣式層疊。
當然,我們在控制臺輸入 document.styleSheets 看到styleSheets結構:
布局(構建render樹)
有了 DOM樹 和 styleSheets樹,接下來我們就可以將兩棵樹進行合并,生成render樹。
在生成render樹時,瀏覽器首先遍歷 DOM 樹中的所有可見節點,并把這些節點加到布局樹中,而不可見的節點會被布局樹忽略掉,如 head 標簽下面的全部內容,再比如 body.div.span 這個元素,因為它的屬性包含 dispaly:none,所以這個元素也沒有被包進布局樹。
當然,這只是第一步,光有這些標簽和對應的樣式是無法繪出頁面圖的,渲染進程還需要計算出每一個標簽所對應在頁面上的物理位置,再將其位置存儲到render樹中。
分層
雖然有了render樹及對應的物理坐標,但瀏覽器也不能直接進行頁面繪制,因為頁面上還涉及許多復雜的樣式:transform, animation 動畫、scroll,z-indexing改變層級等等,瀏覽器則為這些特殊的節點建立一個對應圖層,生成圖層樹(LayerTree),將這些圖層合并在一起,就是一整個頁面的樣式(類似于 photoshop 的圖層)。
那什么時候會被提升為一個專門的圖層,哪些應該被包含在同一圖層?
1、擁有層疊上下文屬性的元素
什么是層疊上下文?其實就是我們熟悉使用的z-index,MDN上是這么定義的:
其中有一句話很重要:
不知你在使用z-index時,有沒有遇到這樣一個情況:
有時,你想要某一個圖片或者文字 置于 某一塊 的上方,于是使用z-index進行層級提升,但是就算設置了z-index確沒有起作用。
正式因為 子級層疊上下文的 z-index 值只在父級中才有意義 ,只有當 父級的 position 為 absolut 或者 relative 時才有效。
2、需要剪裁的地方也會被創建為圖層。
當父容器的寬高不足以撐起子容器的寬高,出現滾動條 或者 設置 父容器 為overflow :hode 等等,子容器頁面就會被裁剪,這時瀏覽器也會為其創建出單獨的圖層。
如何查看圖層?
打開 chrome 控制臺,選擇 Layers, 點擊旋轉按鈕,對圖層進行拖拽到有一定的傾斜度時,便能很直觀的看到頁面的圖層分布 :
繪制
創建完圖層后,接下來就是對圖層進行繪制繪制,簡單的說就是將圖層重疊在一起。
如果給我們一張圖,我們會怎樣進行繪制呢?
一般我們會對這張圖進行拆分:
1、先畫出最外層的紅色框圖
2、在畫出中間層綠色框圖
3、最后畫出里面層黃色框圖
瀏覽器也是如此,將這些圖層拆分為一條條的指令,然后一條一條逐步執行,最后進行繪制:
分塊
為什么需要分塊? 再此之前我們需要了解一下什么是視口:我們在當前屏幕區域能看到的模塊就叫視口。當頁面內容很長時,頁面就會出現滾動條,但是當前視口大小有限,我們只能看到一部分,所以在這種情況下,要繪制出所有圖層內容的話,就會產生太大的開銷,而且也沒有必要。
這個時候渲染進程會再次將這些圖層分成很多圖塊。
格珊化
什么是格珊化?
渲染進程將這些圖層分成很多圖塊后,然后按照視口附近的圖塊來通過 柵格化 優先生成位圖。所謂柵格化,是指將圖塊轉換為位圖。而圖塊是柵格化執行的最小單位。
最后,我們來看一張流程圖:
之前的生成DOM樹、styleSheets樹、render 樹、分層、繪制都是在渲染引起的主線程中運行的, 繪制列表記錄好繪制順序和繪制指令的列表后,將其提交給渲染引擎中的合成線程,渲染進程還維護了一個柵格化的線程池,所有的圖塊柵格化都是在線程池內執行的。通常,柵格化過程都會使用 GPU 來加速生成,使用 GPU 生成位圖的過程叫快速柵格化,或者 GPU 柵格化,生成的位圖被保存在 GPU 內存中。
合成與顯示
一旦所有圖塊都被光柵化,合成線程就會生成一個繪制圖塊的命令——“DrawQuad”,然后將該命令提交給瀏覽器進程。瀏覽器進程里面有一個叫 viz 的組件,用來接收合成線程發過來的 DrawQuad 命令,然后根據 DrawQuad 命令,將其頁面內容繪制到內存中,最后再將內存顯示在屏幕上。
至此,整個渲染流程就走完了,總結為以下8步:
1、渲染進程將 HTML 內容轉換為能夠讀懂的 DOM 樹結構。
2、渲染引擎將 CSS 樣式表轉化為瀏覽器可以理解的 styleSheets樹,并計算好 DOM 節點的樣式。
3、將DOM與styleSheets樹進行合成,創建布局(render)樹,并計算元素的布局信息。
4、對布局樹進行分層,并生成分層樹。為每個圖層生成繪制列表,并將其提交到合成線程。
5、合成線程將圖層分成圖塊。
6、在光柵化線程池中將圖塊轉換成位圖。
7、合成線程發送繪制圖塊命令 DrawQuad 給瀏覽器進程。
8、瀏覽器進程根據 DrawQuad 消息生成頁面,并顯示到顯示器上。
最后拋出兩個問題:
1、為什么在優化 Web 性能的方法中,減少重繪、重排是一種很好的優化方式?
結合上文我們了解到,在布局這一過程中,將DOM樹與styleSheets 合成render樹后,渲染進程還需要計算出每一個標簽所對應在頁面上的物理位置,再將其位置存儲到render樹中,在執行下一步。
如果我們對頁面進行了重排(改變標簽的寬高、顯示隱藏等物理層面的幾何屬性),那么渲染引擎將會把這一整套渲染流程重新跑一遍,浪費時間和空間。
如果我們對頁面進行了重繪(改變標簽的顏色、類名等樣式屬性),那么渲染引擎會直接進入 繪制 階段,相較與重排,也提升了不少性能。
如果我們的操作不涉及重排和重繪,那么渲染引擎會直接進入 合成 階段,大大的提高了性能。
2、如果下載 CSS/JS 文件阻塞了,會阻塞 DOM 樹的合成嗎?會阻塞頁面的顯示嗎?
答案是肯定的,不論CSS還是JS文件下載阻塞,都會阻塞后續的流程。當從服務器接收HTML頁面的第一批數據時,DOM解析器就開始工作了。
第一種情況:在解析過程中,如果遇到了JS腳本,如下所示:
那么DOM解析器會先執行JavaScript腳本,執行完成之后,再繼續往下解析。
第二種情況:我們內聯的腳本替換成js外部文件,如下所示:
<html><body>哈哈哈<script type="text/javascript" src="foo.js"></script></body> </html>這種情況下,當解析到JavaScript的時候,會先暫停DOM解析,并下載foo.js文件,下載完成之后執行該段JS文件,然后再繼續往下解析DOM。這就是JavaScript文件為什么會阻塞DOM渲染。
第三種情況,還是看下面代碼:
<html><head><style type="text/css" src = "theme.css" /></head><body><p>哈哈哈</p><script>let e = document.getElementsByTagName('p')[0]e.style.color = 'blue'</script></body> </html>當我在JavaScript中訪問了某個元素的樣式,那么這時候就需要等待這個樣式被下載完成才能繼續往下執行,所以在這種情況下,CSS也會阻塞DOM的解析。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的浏览器从输入URL到页面渲染过程 ——页面渲染流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Guns根据条件查询数据_入门试炼04
- 下一篇: 系统架构设计师 - 软件架构设计 - 架