瀏覽器(browser application)是專門用來訪問和瀏覽萬維網頁面的客戶端軟件,也是現代計算機系統中應用最爲普遍的軟件之一,其重要性不言而喻。前端工程師做爲負責程序頁面顯示的工程師,須要直接與瀏覽器打交道。本文將詳細介紹瀏覽器的工做原理css
瀏覽器的組成以下圖所示html
主要組件包括:前端
1. 用戶界面 - 包括地址欄、後退/前進按鈕、書籤目錄等,也就是所看到的除了用來顯示所請求頁面的主窗口以外的其餘部分node
2. 瀏覽器引擎 - 用來查詢及操做渲染引擎的接口web
3. 渲染引擎 - 用來顯示請求的內容,例如,若是請求內容爲html,它負責解析html及css,並將解析後的結果顯示出來。正則表達式
4. 網絡 - 用來完成網絡調用,例如http請求,它具備平臺無關的接口,能夠在不一樣平臺上工做。chrome
5. UI後端 - 用來繪製相似組合選擇框及對話框等基本組件,具備不特定於某個平臺的通用接口,底層使用操做系統的用戶接口。編程
6. JS解釋器 - 用來解釋執行JS代碼。後端
7. 數據存儲 - 屬於持久層,瀏覽器須要在硬盤中保存相似cookie的各類數據,HTML5定義了web database技術,這是一種輕量級完整的客戶端存儲技術數組
瀏覽器內核分紅兩部分:渲染引擎和js引擎,因爲js引擎愈來愈獨立,內核就傾向於只指渲染引擎,負責請求網絡頁面資源加以解析排版並呈現給用戶
默認狀況下,渲染引擎能夠顯示html、xml文檔及圖片,它也能夠藉助插件顯示其餘類型數據,例如使用PDF閱讀器插件,能夠顯示PDF格式
【渲染引擎】
firefox使用gecko引擎
IE使用Trident引擎,2015年微軟推出本身新的瀏覽器,原名叫斯巴達,後更名edge,使用edge引擎
opera最先使用Presto引擎,後來棄用
chrome\safari\opera使用webkit引擎,13年chrome和opera開始使用Blink引擎
UC使用U3引擎
QQ瀏覽器和微信內核使用X5引擎,16年開始使用Blink引擎
【js引擎】
老版本IE使用Jscript引擎,IE9以後使用Chakra引擎,edge瀏覽器仍然使用Chakra引擎
firefox使用monkey系列引擎
safari使用的SquirrelFish系列引擎
Opera使用Carakan引擎
chrome使用V8引擎。nodeJs其實就是封裝了V8引擎
從資源的下載到最終的頁面展示,渲染流程可簡單地理解成一個線性串聯的變換過程的組合,原始輸入爲URL地址,最終輸出爲頁面Bitmap,中間依次通過了Loader、Parser、Layout和Paint模塊
渲染引擎的核心流程以下所示
【Loader】
Loader模塊負責處理全部的HTTP請求以及網絡資源的緩存,至關因而從URL輸入到Page Resource輸出的變換過程。HTML頁面中一般有外鏈的JS/CSS/Image資源,爲了避免阻塞後續解析過程,通常會有兩個IO管道同時存在,一個負責主頁面下載,一個負責各類外鏈資源的下載
注意:雖然大部分狀況下不一樣資源能夠併發下載異步解析(如圖片資源能夠在主頁面解析顯示完成後再被顯示),但JS腳本可能會要求改變頁面,所以有時保持執行順序和下載管道後續處理的阻塞是不可避免的
【Parser】
一、解析HTML
Parser模塊主要負責解析HTML頁面,完成從HTML文本到HTML語法樹再到文檔對象樹(Document Object Model Tree,DOM Tree)的映射過程
HTML語法樹生成是一個典型的語法解析過程,能夠分紅兩個子過程:詞法解析和語法解析
詞法解析按照詞法規則(如正則表達式)將HTML文本分割成大量的標記(token),並去除其中無關的字符如空格。語法解析按照語法規則(如上下文無關文法)匹配Token序列生成語法樹,一般有自上而下和自下而上兩種匹配方式
瀏覽器內核中對HTML頁面真正的內部表示並非語法樹,而是W3C組織規範的文檔對象模型(Document Object Model,DOM)。DOM也是樹形結構,以Document對象爲根。DOM節點基本和HTML語法樹節點一一對應,所以在語法解析過程當中,一般直接生成最終的DOM樹
二、解析CSS
頁面中全部的CSS由樣式表CSSStyleSheet集合構成,而CSSStyleSheet是一系列CSSRule的集合,每一條CSSRule則由選擇器CSSStyleSelector部分和聲明CSSStyleDeclaration部分構成,而CSSStyleDeclaration是CSS屬性和值的Key-Value集合
CSS解析完畢後會進行CSSRule的匹配過程,即尋找知足每條CSS規則Selector部分的HTML元素,而後將其Declaration部分應用於該元素。實際的規則匹配過程會考慮到默認和繼承的CSS屬性、匹配的效率及規則的優先級等因素
三、解析Javascript
JavaScript通常由單獨的腳本引擎解析執行,它的做用一般是動態地改變DOM樹(好比爲DOM節點添加事件響應處理函數),即根據時間(timer)或事件(event)映射一棵DOM樹到另外一棵DOM樹。
簡單來講,通過了Parser模塊的處理,內核把頁面文本轉換成了一棵節點帶CSS Style、會響應自定義事件的Styled DOM樹
【layout】
Layout過程就是排版,它包含兩大過程
一、建立渲染樹
佈局樹(或者叫作渲染樹、Render Tree)和DOM樹大致能一一對應,二者在內核中同時存在但做用不一樣。DOM樹是HTML文檔的對象表示,同時也做爲JavaScript操縱HTML的對象接口。Render樹是DOM樹的排版表示,用以計算可視DOM節點的佈局信息(如寬、高、座標)和後續階段的繪製顯示
注意:並不是全部DOM節點均可視,也就是並不是全部DOM樹節點都會對應生成一個Render樹節點。例如head標籤(HTMLHeadElement節點)不表示任何排版區域,於是沒有對應的Render節點。同時,DOM樹可視節點的CSS Style就是其對應Render樹節點的Style
二、計算佈局
佈局就是安排和計算頁面中每一個元素大小位置等幾何信息的過程。HTML採用流式佈局模型,基本的原則是頁面元素在順序遍歷過程當中依次按從左至右、從上至下的排列方式肯定各自的位置區域
一個HTML元素對應一個以CSS盒子模型描述的方塊區域,HTML元素分紅兩個基本類型,Inline和Block。Inline元素不會換行,按從左到右來佈局。Block元素的出現意味着須要從上至下換到下一行來佈局。除了這種基本的順序按照元素的Inline和Block來進行流式佈局以外,還有特殊指定的一些佈局方式,如Absolute/Fixed/Relative三種定位佈局以及Float浮動佈局
簡單狀況下,佈局能夠順序遍歷一次Render樹完成,但也有須要迭代的狀況。當祖先元素的大小位置依賴於後代元素或者互相依賴時,一次遍歷就沒法完成佈局,如Table元素的寬高未明確指定而其下某一子元素Tr指定其高度爲父Table高度的30%的狀況
通過了Layout階段的處理,把帶Style的DOM樹變換成包含佈局信息和繪製信息的Render樹,接下來的顯示工做就交由Paint模塊進行操做了
【Paint】
Paint模塊負責將Render樹映射成可視的圖形,它會遍歷Render樹調用每一個Render節點的繪製方法將其內容顯示在一塊畫布或者位圖上,並最終呈如今瀏覽器應用窗口中成爲用戶看到的實際頁面。每一個節點對應的大小位置等信息都已經由Layout階段計算好了,節點的內容取決於對應的HTML元素,或是文本,或是圖片,或是UI控件
一般狀況下,佈局和繪製是至關耗時的操做。若是DOM樹每次略有改動都要從新佈局和繪製一次,效率會至關低下。所以,通常瀏覽內核都會實現一種增量佈局和增量繪製的方式。當一個DOM樹節點(或者它的子節點)內容或者樣式發生變化時,內核會肯定其影響範圍,在佈局階段會標記出受該節點佈局影響的其餘節點(好比多是子節點),在繪製階段則會標記出一個Dirty區域並通知系統重繪
按照HTML相關規範,頁面元素的CSS屬性也規定了其繪製順序,如根據不一樣Layer必須按順序繪製,不然覆蓋疊加效果會出現錯誤,如元素的邊框輪廓和內容背景的繪製次序也有規定
使用瀏覽器上網時,首先會在地址欄輸入一個網址,瀏覽器會依據網址向服務器發送資源請求,服務器解析請求,並將相關數據資源傳送回給瀏覽器,這些數據資源包括Page的描述文檔、圖片、JavaScript腳本、CSS等。此後,瀏覽器引擎會對數據進行解碼、解析、排版、繪製等操做,最終呈現出完整的頁面。Loader是瀏覽器的排頭兵,負責資源加載的工做
Loader在瀏覽器中承上啓下,一方面它做爲網絡模塊的客戶,經過網絡模塊來加載資源;另外一方面它爲Parser模塊加載頁面的內容,控制着瀏覽器後續的解析以及繪製過程
Loader有兩條資源加載路徑:主資源加載路徑和派生資源加載路徑。這兩類資源的加載過程很有不一樣,好比對資源加載失敗的處理,主資源下載失敗會有報錯提示,而派生資源如圖片下載失敗,每每只顯示一個佔位
在地址欄輸入新地址或者在已經打開的頁面中點擊連接,都會觸發主資源的加載流程,隨着主資源在HTTP協議的傳輸下分段到達,瀏覽器的Parser模塊解析主資源的內容,生成派生資源對應的DOM結構,而後根據需求觸發派生資源的加載流程。主資源的加載是馬上發起的,而派生資源則可能會爲了優化網絡,在隊列中等待
主資源和派生資源的加載還有一個區別,在Android 4.2版本中主資源是沒有緩存的,而派生資源是有緩存機制的。這裏的緩存指的是Memory Cache,用於保存原始數據(好比CSS、JS等),以及解碼過的數據,經過Memory Cache能夠節省網絡請求和圖片解碼的時間
瀏覽器在加載主資源後,主資源會被解碼,而後進行解析,生成DOM(文檔對象模型)樹。在解析過程當中,若是遇到<img的起始標籤,會建立相應的image元素HTMLImageElement,接着依據img標籤的內容設置HTMLImageElement的屬性。在設置src屬性時,會觸發圖片資源加載,發起加載資源請求
緩存在瀏覽器中也獲得了普遍的應用,對提升用戶體驗起到了重要做用。在瀏覽器中,主要存在三種類型的緩存:Page Cache、Memory Cache、Disk Cache。這三類Cache的容量都是能夠配置的,好比限制Memory Cache最大不超過30MB,Page Cache緩存的頁面數量不超過5個等
Page Cache:是將瀏覽的頁面狀態臨時保存在緩存中,以加速頁面返回等操做
Memory Cache:瀏覽器內部的緩存機制,對於相同url的資源直接從緩存中獲取,不需從新下載
Disk Cache:資源加載緩存和服務器進行交互,服務器端能夠經過HTTP頭信息設置網頁要不要緩存。
【內存緩存】
Memory Cache,顧名思義內存緩存,其主要做用爲緩存頁面使用各類派生資源。在使用瀏覽器瀏覽網頁時,尤爲是瀏覽一個大型網站的不一樣頁面時,常常會遇到網頁中包含相同資源的狀況,應用Memory Cache能夠顯著提升瀏覽器的用戶體驗,減小無謂的內存、時間以及網絡帶寬開銷
【頁面緩存】
Page Cache,即頁面緩存。用來緩存用戶訪問過的網頁DOM樹、Render樹等數據。設計頁面緩存的意圖在於提供流暢的頁面前進、後退瀏覽體驗。幾乎全部的現代瀏覽器都支持頁面緩存功能
若是瀏覽器沒有頁面緩存,用戶點擊連接訪問新頁面時,原頁面的各類派生資源、JavaScript對象、DOM樹節點等佔據的內存通通被回收,此後當用戶點擊後退按鈕以瀏覽原頁面時,瀏覽器必須先要從新從網絡下載相關資源,而後進行解碼、解析、佈局、渲染一系列操做,最後才能爲用戶呈現出頁面,這無疑增長了用戶的等待時間,影響了用戶的使用體驗
全部的派生資源加載時都會與Memory Cache關聯,若是Memory Cache中有資源的備份且條件合適,則能夠直接從Memory Cache中加載。而Page Cache只會在用戶點擊前進或後退按鈕時纔會被查詢,若是頁面符合緩存條件並被緩存了,則直接從Page Cache中加載。即便某個須要被加載的頁面在Page Cache中有備份,但若觸發加載的緣由是用戶在地址欄輸入url或點擊連接,則頁面仍然是經過網絡加載。也就是說Page Cache並非主資源的通用緩存
【磁盤緩存】
Disk Cache,即磁盤緩存。現代的瀏覽器基本都有磁盤緩存機制,爲了提高用戶的使用體驗,瀏覽器將下載的資源保存到本地磁盤,當瀏覽器下次請求相同的資源時,能夠省去網絡下載資源的時間,直接從本地磁盤中取出資源便可
磁盤緩存即咱們常說的Web緩存,分爲強緩存和協商緩存,它們的區別在於強緩存不發請求到服務器,協商緩存會發請求到服務器
能夠將瀏覽器總體看做一個網頁處理模塊,這個模塊的輸入是網絡上接收到的字節流形式的網頁內容。輸出是三棵樹型邏輯結構:DOM樹、Render樹及RenderLayer樹
瀏覽器的解析過程就是將字節流形式的網頁內容構建成DOM樹、Render樹及RenderLayer樹的過程
瀏覽器的解析對象是網頁內容,網頁內容包括如下三個部分:
一、HTML文檔:超文本標記語言,製做Web頁面的標準語言
二、CSS樣式表(Cascading Style Sheet):級聯樣式表,用來控制網頁樣式,並容許樣式信息與網頁內容相分離的一種標記性語言
三、JavaScript腳本:JavaScript是一種無類型的解釋型腳本語言。經常使用於爲網頁添加動態功能
HTML文檔決定了DOM樹及Render樹的結構。CSS樣式表決定了Render樹上節點的排版佈局方式。JavaScript代碼能夠操做DOM樹,改變DOM樹的結構,也能夠用來給頁面添加更豐富的動態功能
HTML文檔被解析生成DOM樹,由DOM節點建立Render樹節點時,會觸發CSS匹配過程,CSS匹配的結果是RenderStyle實例,這個實例由Render節點持有,保存了Render節點的排版佈局信息。CSS的解析過程便是CSS語法在瀏覽器的內部表示過程,解析的結果是獲得一系列的CSS規則。CSS的匹配過程主要依據CSS選擇器的不一樣優先級進行,高優先級選擇器優先適用。根據網頁上定義的JavaScript腳本的不一樣屬性,JavaScript腳本的下載和執行時機會有所不一樣。JavaScript腳本的執行是由渲染引擎轉交給JS引擎執行的。下面分別看一下HTML、CSS、JavaScript的具體解析和執行
【DOM樹構建】
DOM(Document Object Model,文檔對象模型),是中立於平臺和語言的接口。它容許程序和腳本動態地訪問和更新文檔的內容結構和樣式。DOM是頁面上數據和結構的一個樹形表示,使用DOM接口能夠對DOM樹結構進行操做。DOM規範只是定義了編程接口,沒有對文檔的表示方式作任何限制。以樹狀結構表示DOM文檔是比較廣泛的實現方式。這個樹狀結構就稱爲DOM樹。DOM樹是DOM文檔中的節點按照層次組織構成的。以HTML文檔爲例,每個標籤都對應着DOM樹上的一個節點。因爲是樹形結構表示,這些節點之間的關係也是經過父子或兄弟維繫的
渲染引擎解析HTML文檔的過程就是將字節流形式的網頁內容解析成DOM Tree、Render Tree、Render Layer Tree三棵樹的過程。這個過程能夠分爲解碼、分詞、解析、建樹四個步驟
一、解碼:將網絡上接收到的通過編碼的字節流,解碼成Unicode字符
二、分詞:按照必定的切詞規則,將Unicode字符流切成一個個的詞語(Tokens)
三、解析:根據詞語的語義,建立相應的節點(Node)
四、建樹:將節點關聯到一塊兒,建立DOM樹、Render樹和RenderLayer樹
【Render樹構建】
Render樹用於表示文檔的可視信息,記錄了文檔中每一個可視元素的佈局及渲染方式。Render樹與DOM樹是同時建立的
HTML頁面經過CSS控制頁面佈局,因此RenderObject須要知道自身的CSS屬性,CSSStyleSelector負責爲元素提供RenderStyle。RenderObject包含自身的RenderStyle的引用。CSSStyleSelector是在CSS解析過程當中生成的。Render節點建立後,就會被attach到Render樹上
當前Render節點的父節點負責將當前Render節點插入到合適的位置,當父Render節點設置好當前Redner節點的先後兄弟節點後,當前Render節點就attach到了Render樹上
RenderObject是Render樹全部節點的基類,做用相似於DOM樹的Node類。這個類存儲了繪製頁面可視元素所須要的樣式及佈局信息,RenderObject對象及其子類都知道如何繪製本身。事實上繪製Render樹的過程就是RenderObject按照必定順序繪製自身的過程。DOM樹上的節點與Render樹上的節點並非一一對應的。只有DOM樹的根節點及可視節點纔會建立對應的RenderObject節點
【Render Layer樹構建】
RenderLayer樹以層爲節點組織文檔的可視信息,網頁上的每一層對應一個RenderLayer對象。RenderLayer樹能夠看做Render樹的稀疏表示,每一個RenderLayer樹的節點都對應着一棵Render樹的子樹,這棵子樹上全部Render節點都在網頁的同一層顯示
RenderLayer樹是基於RenderObject樹構建的,知足必定條件的RenderObject纔會創建對應的RenderLayer節點。下面是RenderLayer節點的建立條件:
一、網頁的root節點
二、有顯式的CSS position屬性(relative,absolute,fixed)
三、元素設置了transform
四、元素是透明的,即opacity不等於1
五、節點有溢出(overflow)、alpha mask或者反射(reflection)效果。
六、元素有CSS filter(濾鏡)屬性
七、2D Canvas或者WebGL
八、Video元素
當知足這些條件之一時,RenderLayer實例被建立。RenderObject節點與RenderLayer節點是多對一的關係,即一個或多個RenderObject節點對應一個RenderLayer節點。這一點能夠理解爲網頁的一層中可包含一個或多個可視節點。RenderLayer樹的根節點是RenderView實例
RenderLayer的一個重要用途是能夠在繪製時實現合成加速,即每個RenderLayer對應系統的一塊後端存儲,這樣在網頁內容發生更新時,能夠只更新有變化的RenderLayer,從而提升渲染效率
【CSS解析】
CSS解析過程便是將原始的CSS文件中包含的一系列CSS規則表示成渲染引擎中相應規則類的實例的過程
解析選擇器和解析屬性值的過程均可能執行屢次。渲染引擎爲解析出來的選擇器建立一個CSSSelector實例,因爲可能存在多個選擇器,渲染引擎使用CSSSelectorList類保存全部的選擇器,併爲解析出來的每一個屬性值對建立CSSProperty實例
CSS文件解析完成後,CSS規則都保存在了CSSRuleList實例中,這些規則會在建立Render節點的過程當中使用到。Node節點經過調用CSSStyleSelector實例的StyleForElement()函數爲Render節點建立RenderStyle實例。有了RenderStyle實例才能夠建立RenderObject實例。RenderStyle描述了RenderObject的排版佈局信息,也就是匹配後的樣式信息
CSS規則匹配過程就發生在CSSStyleSelector建立RenderStyle實例的過程當中。CSSStyleSelector負責從CSSRuleList中找出全部匹配相應元素的樣式屬性的Property-Value對
CSS規則匹配是按照選擇器類型的優先級進行的,不一樣類型的選擇器具備不一樣的優先級。經常使用選擇器類型的優先級以下:
ID選擇器 > 類型選擇器 > 標籤選擇器 > 相鄰選擇器 > 子選擇器 > 後代選擇器
全部匹配上元素的CSSStyleRule都會放入一個結果數組中。渲染引擎會對全部存入結果數組中的規則按照選擇器的優先級進行排序,高優先級規則優先使用,最終使用的規則會用來建立RenderStyle實例。RenderStyle實例由RenderObject對象持有,RenderObject就是根據RenderStyle中包含的信息,進行自身排版繪製
【JS執行】
JavaScript是一種解釋型的動態腳本語言,須要由專門的JavaScript引擎執行。Android 4.2版本的WebKit採用的JavaScript執行引擎爲V8,V8是由Google支持的開源項目。它的設計目的就是追求更高的性能,最大限度地提升JavaScript的執行效率。與JavaScriptCore等傳統引擎不一樣,V8把JavaScript代碼直接編譯成機器碼運行,比起傳統「中間代碼+解釋器」的引擎,性能優點很是明顯。JS代碼一般保存在獨立的JS文件中,經過script標籤引用到HTML文檔中
DOM樹建立過程當中遇到script標籤時會建立HTMLScriptElement實例。HTMLScript-Element的父類ScriptElement中包含了對JS腳本的全部處理,包括下載、緩存、執行等。根據script標籤的不一樣屬性,JS腳本加載後的執行時機會有所不一樣。若是script標籤中使用了async屬性,JS腳本加載過程不會阻塞文檔解析,腳本加載完成後會當即執行。若是sript標籤中使用了defer屬性,JS腳本加載過程不會阻塞文檔解析,當腳本的執行要等獲得文檔解析完成以後。對於外部引用的腳本文件,從腳本下載到腳本執行完,文檔解析過程會一直被阻塞
WebKit渲染引擎的渲染方式分爲軟件渲染和硬件渲染,這兩種渲染方式均可以分紅兩個大的過程:一是獲得網頁的繪製信息;二是將網頁繪製信息轉換成像素並上屏
獲得網頁繪製信息的過程須要遍歷RenderLayer樹,將RenderLayer樹包含的網頁繪製信息先記錄下來,等到渲染時使用。記錄網頁繪製信息這一步對渲染引擎而言,就是繪製的過程,渲染引擎自己並不知道繪製命令是否有被真正執行
【軟件渲染】
軟件渲染的流程可歸納爲如下三步:
一、從SurfaceFlinger得到一塊圖形緩衝區
二、在封裝這塊圖形緩衝區的SkCanvas上執行網頁繪製命令
三、將繪製好的圖形緩衝區歸還SurfaceFlinger
軟件渲染實現簡單,網頁內容直接繪製到一塊圖形緩衝區上,內存佔用更少。不足之處在於,因爲網頁內容繪製在同一塊圖形緩衝區上,更新網頁內容時須要所有更新,沒法局部更新
【硬件渲染】
相較於軟件渲染,硬件渲染實現比較複雜,網頁內容須要先繪製到一塊SkBitmap上,再經過圖形緩衝區上傳給GPU,須要更多內存
硬件渲染是指網頁各層的合成是經過GPU完成的,它採用分塊渲染的策略,分塊渲染是指:網頁內容被一組Tile覆蓋,每塊Tile對應一個獨立的後端存儲,當網頁內容更新時,只更新內容有變化的Tile。分塊策略能夠作到局部更新,渲染效率更高
硬件渲染的過程分爲如下5步:
一、在一塊封裝了SkBitmap的SkCanvas上執行一個Tile覆蓋的網頁信息的繪製命令;
二、將每一個Tile對應的SkBitmap copy到從SurfaceFlinger得到的一塊圖形緩衝區中;
三、將全部Tile對應的圖形緩衝區上傳GPU進行合成;
四、將合成好的網頁內容blit到Tile對應的與OnScreen FrameBuffer相關聯的Texture;
五、經過GPU對Tile對應的Texture進行硬件繪製
開啓硬件渲染,即合成加速,會爲須要單獨繪製的每一層建立一個GraphicsLayer
合成加速狀況下,每一層網頁內容都對應一個後端存儲,這塊後端存儲由平臺實現,Android 4.2平臺提供的後端存儲是GraphicsLayerAndroid。開始記錄網頁繪製命令時,RenderLayerCompositor負責控制RenderLayer的遍歷,RenderLayer包含的繪製信息最終記錄在其後端存儲上,即GraphicsLayerAndroid包含的PicturePile實例中
一個RenderLayer對象若是須要後端存儲,它會建立一個RenderLayerBacking對象,該對象負責Renderlayer對象所須要的各類存儲。理想狀況下,每一個RenderLayer均可以建立本身的後端存儲,事實上不是全部RenderLayer都有本身的RenderLayerBacking對象。若是一個RenderLayer對象被像樣的建立後端存儲,那麼將該RenderLayer稱爲合成層(Compositing Layer)
哪些RenderLayer能夠是合成層呢?若是一個RenderLayer對象具備如下的特徵之一,那麼它就是合成層:
一、RenderLayer具備CSS 3D屬性或者CSS透視效果。
二、RenderLayer包含的RenderObject節點表示的是使用硬件加速的視頻解碼技術的HTML5 」video」元素。
三、 RenderLayer包含的RenderObject節點表示的是使用硬件加速的Canvas2D元素或者WebGL技術。
四、RenderLayer使用了CSS透明效果的動畫或者CSS變換的動畫。
五、RenderLayer使用了硬件加速的CSSfilters技術。
六、RenderLayer使用了剪裁(clip)或者反射(reflection)屬性,而且它的後代中包括了一個合成層。
七、RenderLayer有一個Z座標比本身小的兄弟節點,該節點是一個合成層
因此,進行硬件加速的渲染流程以下所示
重繪和迴流是在頁面渲染過程當中很是重要的兩個概念。頁面生成之後,腳本操做、樣式表變動,以及用戶操做均可能觸發重繪和迴流
【迴流】
迴流reflow是firefox裏的術語,在chrome中稱爲重排relayout
迴流是指窗口尺寸被修改、發生滾動操做,或者元素位置相關屬性被更新時會觸發佈局過程,在佈局過程當中要計算全部元素的位置信息。因爲HTML使用的是流式佈局,若是頁面中的一個元素的尺寸發生了變化,則其後續的元素位置都要跟着發生變化,也就是從新進行流式佈局的過程,因此被稱之爲迴流
前面介紹過渲染引擎生成的3個樹:DOM樹、Render樹、Render Layer樹。迴流發生在Render樹上。常說的脫離文檔流,就是指脫離渲染樹Render Tree
觸發迴流包括以下操做:
一、DOM元素的幾何屬性變化
二、DOM樹的結構變化
三、獲取下列屬性
offsetTop\offsetLeft\offsetWidth\offsetHeight\scrollTop\scrollLeft\scrollWidth\scrollHeight\clientTop\clientLeft\clientWidth\clientHeight\getComputedStyle()\currentStyle()
四、改變元素的一些樣式
五、調整瀏覽器窗口大小
觸發迴流必定會觸發後續的重繪操做,並且對一個元素的迴流,可能會影響到父級元素。好比子元素浮動後,父元素會出現高度塌陷的狀況。因此,性能優化的重點在於儘可能只觸發小規模的重繪,儘可能不觸發迴流
【重繪】
重繪是指當與視覺相關的樣式屬性值被更新時會觸發繪製過程,在繪製過程當中要從新計算元素的視覺信息,使元素呈現新的外觀
因爲元素的重繪repaint只發生在渲染層 render layer上。因此,若是要改變元素的視覺屬性,最好讓該元素成爲一個獨立的渲染層render layer
下面以元素顯示爲例,進行說明。實現元素顯示隱藏的方式有不少
display: none/block,會引發迴流,從而引發重繪,性能較差
visibility: visibile/hidden,只引發重繪,但因爲沒有成爲一個獨立的渲染層,會引發整個頁面(或當前渲染層)的重繪,性能較好
opacity: 0/1,opacity小於1時,會產生render layer。因此opacity在0、1的變化中,引發了render layer的生成和銷燬,所以,也會引發迴流,從而引發重繪,性能較差。若是opacity: 0/0.9,則只會引發重繪
若是對一個元素使用硬件加速渲染,如具備CSS 3D屬性,則不會進行重繪和迴流。但若是使用硬件渲染的元素過多,會形成GPU的傳輸壓力
【性能優化】
下面列舉一些減小回流次數的方法
一、不要一條一條地修改DOM樣式,而是修改className或者修改style.cssText
二、在內存中屢次操做節點,完成後再添加到文檔中去
三、對於一個元素進行復雜的操做時,能夠先隱藏它,操做完成後再顯示
四、在須要常常獲取那些引發瀏覽器迴流的屬性值時,要緩存到變量中
五、不要使用table佈局,由於一個小改動可能會形成整個table從新佈局。並且table渲染一般要3倍於同等元素時間
此外,將須要屢次重繪的元素獨立爲render layer渲染層,如設置absolute,能夠減小重繪範圍;對於一些進行動畫的元素,能夠進行硬件渲染,從而避免重繪和迴流