瀏覽器渲染頁面的原理及流程


瀏覽器渲染頁面的原理及流程

瀏覽器將域名通過網絡通信從服務器拿到html文件后,如何渲染頁面呢?

1.根據html文件構建DOM樹和CSSOM樹。構建DOM樹期間,如果遇到JS,阻塞DOM樹及CSSOM樹的構建,優先加載JS文件,加載完畢,再繼續構建DOM樹及CSSOM樹。

2.構建渲染樹(Render Tree)。

3.頁面的重繪(repaint)與重排(reflow,也有稱回流)。頁面渲染完成后,若JS操作了DOM節點,根據JS對DOM操作動作的大小,瀏覽器對頁面進行重繪或是重排。

一、構建DOM樹及CSSOM樹

1.1構建DOM樹

HTML 文檔中的所有內容皆是節點,各節點之間擁有層級關系,如父子關系、兄弟關系等,彼此相連,構成DOM樹。最常見的幾種節點有:文檔節點、元素節點、文本節點、屬性節點、注釋節點

DOM節點樹中節點與HTML文檔中內容一一對應,DOM樹構建過程:讀取html文檔,將字節轉換成字符,確定tokens(標簽),再將tokens轉換成節點,以節點構建 DOM 樹。如下圖所示:

                        

 1.2構建CSSOM樹

 CSS文檔中,所有元素皆是節點,與HTML文件中的標簽節點一一對應。CSS中各節點之間同樣擁有層級關系,如父子關系、兄弟關系等,彼此相連,構成CSSOM樹。

在構建DOM樹的過程中,在 HTML 文檔的 head 標簽中遇到 link 標簽,該標簽引用了一個外部CSS樣式表。由於預見到需要利用該CSS資源來渲染頁面,瀏覽器會立即發出對該CSS資源的請求,並進行CSSDOM樹的構建。

CSSOM樹構建過程與DOM樹構建流程一致:讀取CSS文檔,將字節轉換成字符,確定tokens(標簽),再將tokens轉換成節點,以節點構建 CSSOM 樹。如下圖所示:

                                              

.CSS文件,又名層疊樣式表。當CSSOM樹生成節點時,每一個節點首先會繼承其父節點的所有樣式,層疊覆蓋,然后再以"向下級聯"的規則,為該節點應用更具體的樣式,遞歸生成CSSOM樹。譬如,上右圖中第二層的p節點,有父節點body,因此該p將繼承body節點的樣式:"font-size: 16px;"。然后再應用該p節點自身的樣式:"font-weight: bold;"。所以最終該p節點的樣式為:"font-size: 16px;font-weight: bold;"。

1.3加載JS

若在構建DOM樹的過程中,當 HTML 解析器遇到一個 script 標記時,即遇到了js,將立即阻塞DOM樹的構建,將控制權移交給 JavaScript 引擎,等到 JavaScript 引擎運行完畢,瀏覽器才會從中斷的地方恢復DOM樹的構建。
其根本原因在於,JS會對DOM節點進行操作,瀏覽器無法預測未來的DOM節點的具體內容,為了防止無效操作,節省資源,只能阻塞DOM樹的構建。譬如,若不阻塞DOM樹的構建,若JS刪除了某個DOM節點A,那么瀏覽器為構建此節點A花費的資源就是無效的。

若在HTML頭部加載JS文件,由於JS阻塞,會推遲頁面的首繪。為了加快頁面渲染,一般將JS文件放到HTML底部進行加載,或是對JS文件執行async或defer加載。

二.構建渲染樹

渲染樹(Render Tree)由DOM樹、CSSOM樹合並而成,但並不是必須等DOM樹及CSSOM樹加載完成后才開始合並構建渲染樹。三者的構建並無先后條件,亦非完全獨立,而是會有交叉,並行構建。因此會形成一邊加載,一邊解析,一邊渲染的工作現象。

構建渲染樹,根據渲染樹計算每個可見元素的布局,並輸出到繪制流程,將像素渲染到屏幕上。

三.頁面的重繪(repaint)重排(reflow)

 3.1重繪(repaint):屏幕的一部分要重繪。渲染樹節點發生改變,但不影響該節點在頁面當中的空間位置及大小。譬如某個div標簽節點的背景顏色、字體顏色等等發生改變,但是該div標簽節點的寬、高、內外邊距並不發生變化,此時觸發瀏覽器重繪(repaint)。

 3.2重reflow:也有稱回流,當渲染樹節點發生改變,影響了節點的幾何屬性(如寬、高、內邊距、外邊距、或是float、position、display:none;等等),導致節點位置發生變化,此時觸發瀏覽器重排(reflow),需要重新生成渲染樹。譬如JS為某個p標簽節點添加新的樣式:"display:none;"。導致該p標簽被隱藏起來,該p標簽之后的所有節點位置都會發生改變。此時瀏覽器需要重新生成渲染樹,重新布局,即重排(reflow)。

注意:重排必將引起重繪,而重繪不一定會引起重排。

何時回引起重排?

當頁面布局和幾何屬性改變時就需要重排。下述情況會發生瀏覽器重排:

1、添加或者刪除可見的DOM元素;

2、元素位置改變——display、float、position、overflow等等;

3、元素尺寸改變——邊距、填充、邊框、寬度和高度

4、內容改變——比如文本改變或者圖片大小改變而引起的計算值寬度和高度改變;

5、頁面渲染初始化;

6、瀏覽器窗口尺寸改變——resize事件發生時;

3.3如何減少和避免重排

Reflow 的成本比 Repaint 的成本高得多的多。一個節點的 Reflow 很有可能導致子節點,甚至父節點以及兄弟節點的 Reflow 。在一些高性能的電腦上也許還沒什么,但是如果 Reflow 發生在手機上,那么這個過程是延慢加載和耗電的。----瀏覽器的渲染原理簡介

1. 直接改變className,如果動態改變樣式,則使用cssText(考慮沒有優化的瀏覽器);

2. 讓要操作的元素進行”離線處理”,處理完后一起更新;

a) 使用DocumentFragment進行緩存操作,引發一次回流和重繪;
b) 使用display:none技術,只引發兩次回流和重繪;
c) 使用cloneNode(true or false) 和 replaceChild 技術,引發一次回流和重繪;

3.不要經常訪問會引起瀏覽器flush隊列的屬性,如果你確實要訪問,利用緩存;

4. 讓元素脫離動畫流,減少回流的Render Tree的規模;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM