【前端性能优化】浏览器渲染原理与性能优化
目錄
- 1. 瀏覽器渲染基本步驟
- 2. 構建DOM樹、CSSOM樹
- 3. 構建渲染樹
- 4. 計算渲染樹的布局
- 5. 將布局渲染到屏幕上
- 6. 渲染優化
1. 瀏覽器渲染基本步驟
瀏覽器主要有以下步驟:
- 瀏覽器通過HTTP協議向服務端請求頁面數據
- 將請求回來的HTML文件解析成DOM樹
- 將請求回來的CSS文件解析成CSSOM樹
- 將DOM樹和CSSOM樹結合在一起,生成渲染樹(render tree)
- 計算渲染樹的布局,這實際上是回流的過程
- 將布局渲染到屏幕上,這實際上是重繪的過程
大致過程如圖所示:
這里主要說說后面解析的過程。
2. 構建DOM樹、CSSOM樹
構建DOM樹:
首先來看HTML文件的解析,在解析過程中,如果遇到 <script>就會停止頁面的解析,先執行標簽中的JavaScript代碼,如果代碼時外聯的形式,也需要等待外聯的JavaScript代碼下載并執行完才繼續執行解析HTML的工作,解析完HTML文件之后,就會觸發DOMContentLoaded 事件,這時就可以操作DOM了。
構建CSSOM樹:
下面來看CSS的解析,我們從上面的圖中可以看到HTML解析和CSS解析是同步進行的,也就是并行處理的,這樣就不會在渲染的內容沒有樣式。在解析過程中,如果遇到script標簽,和上面的處理方式一樣。CSS解析器最終會將CSS解析為CSSStyleSheet(也就是CSSOM樹),具體的結果如下:
CSS是一種渲染阻塞資源(render blocking resource),它需要完全被解析完畢之后才能進入生成渲染樹的環節。
由于CSS有些屬性具有繼承性,后面定義的樣式可能會覆蓋或修改前面的樣式,所以只有當所有的CSS代碼都執行渲染完之后才能進入下一個環節。在CSSOM構建完成之前,頁面都會處于白屏狀態,所以,一般都是在文件的頭部引入CSS文件。
3. 構建渲染樹
當DOM樹和CSSOM樹都解析完之后,就會一起合成渲染樹( Render Tree ),如下圖所示:
在合并生成渲染樹的過程中,有以下幾點需要注意:
- 元素如果被設置為 display:none,在 DOM 樹中依然會顯示,但是在 Render 樹中不會顯示;
- 元素如果被設置為 visibility:none,那么 DOM 樹和 Render 樹中都會顯示;
- 我們經常說的脫離文檔流,其實就是脫離 Render Tree。
4. 計算渲染樹的布局
這一步實際上就是回流的過程。在這一階段,會從渲染樹的根節點開始遍歷,由于渲染樹的每個節點都是一個Render Object 對象,這個對象包含元素的的寬高、位置、顏色、內容等信息。所以瀏覽器會根據這些信息來確定每個節點對象在頁面上的位置和大小,這一階段輸出的就是盒子模型,它會精確捕獲每個元素在屏幕內的確切位置和大小,不過需要注意的是:設置了float,absoulte,fixed的元素會發生位置偏移。
5. 將布局渲染到屏幕上
在繪制階段,瀏覽器會遍歷渲染樹,調用渲染器的paint()方法在屏幕上顯示其內容。
上述五個步驟都是瀏覽器渲染進程中的GUI渲染線程完成的。
GUI渲染線程主要的工作如下:
- 負責渲染瀏覽器頁面,解析HTML、CSS,構建DOM樹、CSSOM樹、渲染樹和繪制頁面
- 當界面需要重繪或由于某種操作引發回流時,該線程就會執行
6. 渲染優化
針對JavaScript:
JavaScript既會阻塞HTML的解析,也會阻塞CSS的解析。因此我們可以對JavaScript的加載方式進行改變,來進行優化:
(1)盡量將JavaScript文件放在body的最后
(2) body中間盡量不要寫<script>標簽
(3)- <script>標簽的方式有三種,有一種就是我們常用的直接引入,還有兩種就是使用 async 屬性和 defer 屬性來異步引入,兩者都是去異步加載外部的JS文件,不會阻塞DOM的解析(盡量使用異步加載)。三者的區別如下:
- script 立即停止頁面渲染去加載資源文件,當資源加載完畢后立即執行js代碼,js代碼執行完畢后繼續渲染頁面
- async 是在下載完成之后,立即異步加載,加載好后立即執行,多個帶async屬性的標簽,不能保證加載的順序
- defer 是在下載完成之后,立即異步加載。加載好后,如果 DOM 樹還沒構建好,則先等 DOm 樹解析好再執行;如果DOM樹已經準備好,則立即執行。多個帶defer屬性的標簽,按照順序執行
針對CSS:
使用css有三種方式:使用link、@import、內聯樣式,其中link和@import都是導入外部樣式。它們之間的區別:
- link:瀏覽器會派發一個新等線程(HTTP線程)去加載資源文件,與此同時GUI渲染線程會繼續向下渲染代碼
- @import:GUI渲染線程會暫時停止渲染,去服務器加載資源文件,資源文件沒有返回之前不會繼續渲染(阻礙瀏覽器渲染)
- style:GUI直接渲染
另外外部樣式如果長時間沒有加載完畢,瀏覽器為了用戶體驗,會使用瀏覽器會默認樣式,確保首次渲染的速度。所以CSS一般寫在headr中,讓瀏覽器盡快發送請求去獲取css樣式。
所以,在開發過程中,導入外部樣式使用link,而不用@import。如果css少,盡可能采用內嵌樣式,直接寫在style標簽中。
針對DOM樹、CSSOM樹:
可以通過以下幾種方式來減少渲染的時間:
- HTML文件的代碼層級盡量不要太深
- 使用語義化的標簽,來避免不標準語義化的特殊處理
- 減少CSSD代碼的層級,因為選擇器是從左向右進行解析的
減少回流與重繪:
這里就不多說了,參考《【前端性能優化】回流與重繪》
最后,再補充一個知識點:Load 和 DOMContentLoaded 區別是什么?
- Load 事件觸發代表頁面中的 DOM,CSS,JS,圖片已經全部加載完畢。
- DOMContentLoaded 事件觸發代表初始的 HTML 被完全加載和解析,不需要等待 CSS,JS,圖片加載
總結
以上是生活随笔為你收集整理的【前端性能优化】浏览器渲染原理与性能优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android FTP 客户端 上传/下
- 下一篇: 浏览器渲染原理及css书写顺序