瀏覽器渲染原理(性能優化之如何減小重排和重繪)

繼續上篇《瀏覽器地址欄裏輸入URL後的全過程javascript

前言

爲何要了解瀏覽器的渲染原理?瞭解瀏覽器的渲染原理有什麼好處?咱們作前端開發爲何非要了解瀏覽器的原理?直接把網頁作出來,什麼需求,直接一把梭,擼完收工很差嗎。css

可是常常會有人會問,什麼是重排重繪html

重排也叫迴流Reflow),重繪Repaint),會影響到瀏覽器的性能,給用戶的感受就是網頁訪問慢,或者網頁會卡頓,不流暢,從而使網頁訪問量降低。前端

因此,想要儘量的避免重排重繪,就須要瞭解瀏覽器的渲染原理java

瀏覽器工做流程

上圖咱們能夠看出,瀏覽器會解析三個模塊:web

  • HTML,SVG,XHTML,解析生成DOM樹。
  • CSS解析生成CSS規則樹。
  • JavaScript用來操做DOM APICSSOM API,生成DOM TreeCSSOM API

解析完成後,瀏覽器會經過已經解析好的DOM TreeCSS規則樹來構造 Rendering Treeshell

  • Rendering Tree 渲染樹並不等同於DOM樹,由於一些像Headerdisplay:none的東西就不必放在渲染樹中了。瀏覽器

  • CSSRule Tree主要是爲了完成匹配並把CSS Rule附加上Rendering性能優化

  • Tree上的每一個Element。也就是DOM結點,即Frame。而後,計算每一個Frame(也就是每一個Element)的位置,這又叫layoutreflow過程。markdown

  • 最後經過調用操做系統Native GUIAPI繪製。

不一樣內核的瀏覽器渲染

上圖是 webkit內核的渲染流程,和整體渲染流程差很少,要構建 HTMLDOM Tree,和 CSS規則樹,而後合併生成 Render Tree,最後渲染。

這個是 MozillaGecko渲染引擎。
整體看來渲染流程差很少,只不過在生成渲染樹或者 Frame樹時,二者叫法不一致, webkit稱之爲 LayoutGecko叫作 Reflow

渲染順序

  • 當瀏覽器拿到一個網頁後,首先瀏覽器會先解析HTML,若是遇到了外鏈的css,會一下載css,一邊解析HTML
  • css下載完成後,會繼續解析css,生成css Rules tree,不會影響到HTML的解析。
  • 當遇到<script>標籤時,一旦發現有對javascript的引用,就會當即下載腳本,同時阻斷文檔的解析,等腳本執行完成後,再開始文檔的解析。

  • DOM樹和CSS規則樹已經生成完畢後,構造 Rendering Tree
  • 調用系統渲染頁面。

什麼狀況會形成重排和重繪。

重排意味着元件的幾何尺寸變了,咱們須要從新驗證並計算Render Tree。是Render Tree的一部分或所有發生了變化。這就是Reflow,或是Layout

重排由於要從新計算Render Tree,並且每個DOM Tree都有一個reflow方法,一旦某個節點發生重排,就有可能致使子元素和父元素甚至是同級其餘元素的reflow,浪費大量的時間從新驗證Render Tree

所以,重排的成本要比重繪高不少。

如下操做會致使重排重繪

  • 刪除,增長,或者修改DOM元素節點。
  • 移動DOM的位置,開啓動畫的時候。
  • 修改CSS樣式,改變元素的大小,位置時,或者將使用display:none時,會形成重排;修改CSS顏色或者visibility:hidden等等,會形成重繪
  • 修改網頁的默認字體時。
  • Resize窗口的時候(移動端沒有這個問題),或是滾動的時候。
  • 內容的改變,(用戶在輸入框中寫入內容也會)。
  • 激活僞類,如:hover。
  • 計算offsetWidthoffsetHeight

若是當前網頁含有一些動畫,或者固定不動元素的網頁時,因爲滾動也會發生重排,一旦發生滾動,當前瀏覽器所承受的壓力很大,就會形成網頁的卡頓,掉幀等狀況。

var bstyle = document.body.style; // cache
 
bstyle.padding = "20px"; // reflow, repaint
bstyle.border = "10px solid red"; // 再一次的 reflow 和 repaint
 
bstyle.color = "blue"; // repaint
bstyle.backgroundColor = "#fad"; // repaint
 
bstyle.fontSize = "2em"; // reflow, repaint
 
// new DOM element - reflow, repaint
document.body.appendChild(document.createTextNode('dude!'));

複製代碼

以上邏輯,幾乎每一步都會形成重排重繪,若是瀏覽器像這樣處理的話,可能現代的瀏覽器沒有咱們使用的那麼流暢了。
所以瀏覽器有一個機制,會把須要重排重繪的先積累着,而後一次性進行重排重繪

固然,不是全部的狀況瀏覽器都是這樣處理的,好比resize或者修改默認字體,對於這些操做,瀏覽器會立馬進行重排

因此咱們在監聽resize事件時,通常咱們都會作防抖節流

如何減小重排和重繪

  • 儘可能避免style的使用,對於須要操做DOM元素節點,從新命名className,更改className名稱。
  • 若是增長元素或者clone元素,能夠先把元素經過documentFragment放入內存中,等操做完畢後,再appendChildDOM元素中。
  • 不要常常獲取同一個元素,能夠第一次獲取元素後,用變量保存下來,減小遍歷時間。
  • 儘可能少使用dispaly:none,可使用visibility:hidden代替,dispaly:none會形成重排visibility:hidden會形成重繪
  • 不要使用Table佈局,由於一個小小的操做,可能就會形成整個表格的重排重繪
  • 使用resize事件時,作防抖節流處理。
  • 對動畫元素使用absolute / fixed屬性。
  • 批量修改元素時,能夠先讓元素脫離文檔流,等修改完畢後,再放入文檔流。

最後

參考文章:

How browsers work

瀏覽器的渲染原理簡介

前端性能優化之重排和重繪

相關文章
相關標籤/搜索