瀏覽器渲染原理


從輸入 URL 到頁面加載完成發生了什么事

DNS解析
TCP連接
發送HTTP請求
服務器處理請求並返回HTTP報文
瀏覽器解析渲染頁面

瀏覽器應該有的功能

網絡;資源管理;網頁瀏覽;多頁面管理;插件與管理;賬戶和同步;安全機制;開發者工具
瀏覽器的主要功能總結起來就是一句話:
	將用戶輸入的url轉變成可視化的圖像

瀏覽器的內核(渲染引擎)

在瀏覽器中有一個最重要的模塊,它主要的作用是將頁面轉變為可視化的圖像結果。這個模塊就是瀏覽器內核,通常它也被稱為渲染引擎。
IE----->Trident
Safari------>WebKit
Chrome;Opera----->Blink
Firefox------>Gecko

渲染引擎

一個渲染引擎主要包括:HTML解析器,CSS解析器,布局layout模塊,javascript引擎,繪圖模塊

渲染過程

1.網頁URL到構建DOM樹的整個過程
	 1) 當用戶輸入URL的時候,Webkit調用資源加載器加載URL對應的網頁
	 2) 加載器依賴網絡模塊建立連接,發送請求並接收答復
	 3) Webkit接收到各種網頁或者資源的數據,其中某些資源可能是同步的或異步獲取的
	 4) 網頁被交給HTML解析器轉變一系列的詞語(Token)
	 5) 解析器根據詞語構建節點(node),形成DOM樹
	 6) 如果節點需要依賴於其他資源,
	 		例如js css 圖片 視頻等,調用資源加載器來加載他們,但是這些都是異步的,
	 		不會阻礙dom樹的繼續創建;順序執行  並發加載
	 		如果資源是css的話
	 			調用CSS解析器解釋將CSS解釋成內部表示結構(CSSDOM)
	 		如果資源是javascript的話
	 			調用Javascript引擎解釋並執行,
	 7)阻塞		
			css阻塞																										
			css 在head中通過link的形式引入會阻塞頁面的渲染	
			為什么?			
			避免閃屏現象																															
			js阻塞
			直接引入的js會阻塞頁面的渲染
			為什么?
			Javascript代碼可能會修改DOM樹的結構
					
	 8) 預解析
WebKit 和 Firefox 都進行了這項優化。在執行js腳本時,其他線程會解析文檔的其余部分,找出並加載需要通過網絡加載的其他資源。通過這種方式,資源可以在並行連接上加載,從而提高總體速度。請注意,預解析器不會修改 DOM 樹,而是將這項工作交由主解析器處理;
預解析器只會解析外部資源(例如外部腳本、樣式表和圖片)的引用。

2.從DOM樹到可視化圖像
	1) CSS文件被CSS解析器解釋成內部表示結構(CSSDOM)
	2) CSS解析器工作完成之后,在DOM樹上附加解釋后的樣式信息,這就是RenderObject樹
	3) RenderObject在創建的同時,Webkit會根據網頁的結構創建RenderLayer,同時構建一個繪圖上下文
	4) 根據繪圖上下文生成最終的圖像(這一過程需要依賴圖形庫)
	 

3.上面介紹的是一個完整的渲染過程,但現代網頁很多都是動態的,這意味着在渲染完成之后,由於網頁的動畫或者用戶的交互,
瀏覽器其實一直在不停地重復執行渲染過程。(重繪重排),以上的數字表示的是基本順序,這不是嚴格一致的,
這個過程可能重復也可能交叉。瀏覽器是一個邊解析邊渲染的過程

css圖層

瀏覽器在渲染一個頁面時,會將頁面分為很多個圖層,圖層有大有小,每個圖層上有一個或多個節點。
在渲染DOM的時候,瀏覽器所做的工作實際上是:
	1. 獲取DOM后分割為多個圖層
	2. 對每個圖層的節點計算樣式結果		(Recalculate style--樣式重計算)
	3. 為每個節點生成圖形和位置			(Layout--重排,回流)
	4. 將每個節點繪制填充到圖層位圖中		(Paint--重繪)
	5. 圖層作為紋理上傳至GPU
	6. 符合多個圖層到頁面上生成最終屏幕圖像	(Composite Layers--圖層重組)

圖層創建的條件

Chrome中滿足以下任意情況就會創建圖層:
	1. 擁有具有3D變換的CSS屬性
	2. 使用加速視頻解碼的<video>節點
	3. <canvas>節點
	4. CSS3動畫的節點
	5. 擁有CSS加速屬性的元素(will-change)
	6. 元素有一個z-index較低且包含一個復合層的兄弟元素(換句話說就是該元素在復合層上面渲染)

重繪(Repaint)

重繪是一個元素外觀的改變所觸發的瀏覽器行為,例如改變outline、背景色等屬性。瀏覽器會根據元素的新屬性重新繪制,
使元素呈現新的外觀。重繪不會帶來重新布局,所以並不一定伴隨重排。

需要注意的是,如果圖層中某個元素需要重繪,那么整個圖層都需要重繪。
比如一個圖層包含很多節點,其中有個gif圖,gif圖的每一幀,都會重回整個圖層的其他節點,然后生成最終的圖層位圖。
所以這需要通過特殊的方式來強制gif圖屬於自己一個圖層(translateZ(0)或者translate3d(0,0,0)
CSS3的動畫也是一樣(好在絕大部分情況瀏覽器自己會為CSS3動畫的節點創建圖層)

重排(Reflow 回流)

渲染對象在創建完成並添加到渲染樹時,並不包含位置和大小信息。計算這些值的過程稱為布局或重排

"重繪"不一定需要"重排",比如改變某個網頁元素的顏色,就只會觸發"重繪",不會觸發"重排",因為布局沒有改變。
 但是,"重排"必然導致"重繪",比如改變一個網頁元素的位置,就會同時觸發"重排"和"重繪",因為布局改變了。

觸發重繪的屬性

		* color								* background									* outline-color
		* border-style						* background-image								* outline
		* border-radius						* background-position							* outline-style
		* visibility						* background-repeat								* outline-width
		* text-decoration					* background-size								* box-shadow

觸發重排(回流)的屬性

盒子模型相關屬性會觸發重布局			定位屬性及浮動也會觸發重布局:				改變節點內部文字結構也會觸發重布局:
		* width								* top											* text-align
		* height							* bottom										* overflow-y
		* padding							* left											* font-weight
		* margin							* right											* overflow
		* display							* position										* font-family
		* border-width						* float											* line-height
		* border							* clear											* vertival-align
		* min-height																		* white-space

常見的觸發重排的操作

Reflow 的成本比 Repaint 的成本高得多的多。DOM Tree 里的每個結點都會有 reflow 方法,
一個結點的 reflow 很有可能導致子結點,甚至父點以及同級結點的 reflow。在一些高性能的電腦上也許還沒什么,
但是如果 reflow 發生在手機上,那么這個過程是非常痛苦和耗電的。

所以,下面這些動作有很大可能會是成本比較高的。
	當你增加、刪除、修改 DOM 結點時,會導致 Reflow , Repaint。
	當你移動 DOM 的位置
	當你修改 CSS 樣式的時候。
	當你 Resize 窗口的時候(移動端沒有這個問題)
	當你修改網頁的默認字體時。
	獲取某些屬性時(width,height...)
	注:display:none 會觸發 reflow,而 visibility:hidden 只會觸發 repaint,因為沒有發生位置變化。

優化

如果我們需要使得動畫或其他節點渲染的性能提高,需要做的就是減少瀏覽器在運行時所需要做的工作(減少1234中的步驟)
	1. 計算需要被加載到節點上的樣式結果(Recalculate style--樣式重計算)
	2. 為每個節點生成圖形和位置(Layout--回流和重布局)
	3. 將每個節點填充到圖層中(Paint Setup和Paint--重繪)
	4. 組合圖層到頁面上(Composite Layers--圖層重組)



1.元素位置移動變換時盡量使用CSS3的transform來代替對top left等的操作
	變換(transform)和透明度(opacity)的改變僅僅影響圖層的組合
2.使用opacity來代替visibility
	透明度竟然不會觸發重繪?
		透明度的改變時,GPU在繪畫時只是簡單的降低之前已經畫好的紋理的alpha值來達到效果,並不需要整體的重繪。
		不過這個前提是這個被修改opacity本身必須是一個圖層,如果圖層下還有其他節點,GPU也會將他們透明化
3.不要使用table布局



4.將多次改變樣式屬性的操作合並成一次操作
	不要一條一條地修改DOM的樣式,預先定義好class,然后修改DOM的className
5.將DOM離線后再修改
	由於display屬性為none的元素不在渲染樹中,對隱藏的元素操作不會引發其他元素的重排。
	如果要對一個元素進行復雜的操作時,可以先隱藏它,操作完成后再顯示。這樣只在隱藏和顯示時觸發2次重排。
6.利用文檔碎片
7.不要把某些DOM節點的屬性值放在一個循環里當成循環的變量
	當你請求向瀏覽器請求一些 style信息的時候,就會讓瀏覽器flush隊列,比如:
		1. offsetTop, offsetLeft, offsetWidth, offsetHeight
		2. scrollTop/Left/Width/Height
		3. clientTop/Left/Width/Height
		4. width,height
	當你請求上面的一些屬性的時候,瀏覽器為了給你最精確的值,需要flush隊列,
	因為隊列中可能會有影響到這些值的操作。即使你獲取元素的布局和樣式信息跟最近發生或改變的布局信息無關,
	瀏覽器都會強行刷新渲染隊列。


8.動畫實現過程中,啟用GPU硬件加速	
9.為動畫元素新建圖層,提高動畫元素的z-index


免責聲明!

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



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