寫在前端性能優化以前你應該知道的 - 瀏覽器的加載和渲染

  前言
javascript

    一直想寫點關於前端性能的東西,後來感受所謂的性能優化最基本的前提是你要知道瀏覽器是如何針對web頁面工做的.後來因爲過年以及換工做等緣由耽擱下來,只好利用這個休息的週末寫一下.     前端

    原本打算好好研究一下關於前端性能優化的一些內容,看了一些發現有的地方不是很明瞭.因此以爲先把瀏覽器加載渲染這個過程摸清楚,本文是多方總結和我本身的一點研究,若是有不對的地方,還請指出,謝謝. java

 
web

    首先咱們要有一個概念,瀏覽器顯示出一個頁面,即便只拿前端拋開服務器和數據庫,也是一個很複雜的過程.儘管它很複雜,但仍是有一的步驟和流程的,瞭解這些步驟你纔會清除的知道哪裏耗費了過多的資源,從而進行人爲的優化.
shell

    在一個頁面上咱們一般會看到種內容,HTML-CSS-Javascript.在一個文件中它們會經過各類方式引入,而後會被瀏覽器分別解析.當咱們經過一個URL地址進入頁面時,工做就開始了.首先瀏覽器將HTML解析爲一個DOM-Tree,而後將CSS規則解析爲一個CSS-Tree,最後則是Javascript的下載和執行.
數據庫


    在這個過程當中,瀏覽器是按照必定順序進行的,其中的任何一個步驟出現問題均可能致使頁面沒法顯示.
瀏覽器

  解析 性能優化

    當完成了上面的解析過程後,瀏覽器引擎會根據這些解析的結果構建出Rendering-Tree,它會生成的規則將CSS樣式應用到對應的element上,而且計算每一個element的位置,這就是Reflow的過程.
服務器

    在這一過程當中,DOM-Tree 的生成相對容易,比較耗費性能的是CSS匹配HTML這一過程,因此對着CSS解析不少地方都有提出:DOM的結構要儘可能簡單,要小,不要過分嵌套,CSS儘可能用class和id.
app

  渲染

    在沒說以前我就要先告訴你們,渲染是一個很消耗性能的過程.這就意味着若是你要優化你的前端性能,能夠在這一部分針對每個動做進行檢查和優化.

    黃色部位就是渲染過程的幾個動做,先進行樣式的計算,而後夠將Rendering-Tree,而後定位座標以及大小等各類樣式屬性,最後畫出來.上面有些線沒有連貫是由於Javascript修改了DOM或者CSS致使必須從新Layout,又或者CSS規則沒有匹配到.

    若是你早先對前端性能有概念,那麼Repaint和Reflow這兩個詞你必定不會陌生.  

    Repaint - 表示頁面上一部分的內容要從新畫,多是顏色什麼的,可是元素的大小和位置不須要改變,也就是不影響其相鄰的內容.

    Reflow - 表示頁面上一部份內容的大小或者位置變化了,這會引發周圍元素的連鎖反應,致使整個Rendering-Tree重構.

    經過描述咱們能夠看到Reflow的動做成本要比Repaint高得多,因此在平時的工做中咱們要儘可能避免瀏覽器的Reflow.對於CSS瀏覽器是能夠並行下載的,可是要注意這其中可能會發生的Reflow.

  JS的加載和執行

    Javascript在整個瀏覽器渲染的進程中始終是個不安份的因素,更多的時候它充當着規則的破壞者這種角色.由於它能夠操做DOM的特性,使得以前生成好的DOM-Tree頗有可能發生改變.

    瀏覽器對於Javascript奉行了兩個原則,首先加載即執行,其次在其執行的期間阻塞其餘內容(包括DOM的解析和其餘資源的下載等).這是由於沒法肯定Javascript的執行會給DOM-Tree或者CSS帶來怎樣的變化,因此在JS執行的狀況下,整個瀏覽器處於單核狀態.看到這你就不難理解爲何不少地方都推薦將CSS寫在頁面最前面,而將Javascript寫在頁面最後的緣由了.

    IE從6開始支持一個defer屬性,它加在<script>標籤中,做用是使Javascript腳本並行下載,而且等到都下載完在順序執行,但僅支持IE.

    HTML5也不甘示弱,加入了相似的async屬性,不過它堅決遵照Javascript加載後當即執行的原則,因此存在弊端,容易使有順序的JS代碼失控,而且不是全部版本的瀏覽器都支持,因此不常使用.

  標準解決方案-動態DOM

    爲了解決Javascript腳本載入的問題,人們又找出經過建立script節點的方式.

function loadjs(script_filename) {
    var script = document.createElement('script');
    script.setAttribute('type', 'text/javascript');
    script.setAttribute('src', script_filename);
    script.setAttribute('id', 'coolshell_script_id');
 
    script_id = document.getElementById('coolshell_script_id');
    if(script_id){
        document.getElementsByTagName('head')[0].removeChild(script_id);
    }
    document.getElementsByTagName('head')[0].appendChild(script);
}
 
var script = 'a.js';
loadjs(script);
    看一下代碼,傳遞一個url參數,而後用建立element的方式建立一個script節點.這一過程就將腳本載入而且執行了.固然其實還有一種Ajax的方式,不過原理差很少,有興趣的能夠自行百度.

  結尾

    其實瀏覽器整個的處理比這寫的要複雜的多,上面的過程只是簡化了.瞭解整個瀏覽器的渲染進程那麼咱們對什麼影響了網頁的加載?這個問題應該有了一點認識,比較重要的一個Repaint和Reflow,另外一個就是JS操做DOM.

    一些建議:

  •     若是能提早定義好一個class去賦值給DOM,就別一個個DOM節點的遍歷而後逐個添加style了,在樓下大喊一句遠比挨個單元去敲門省力.
  •     建立的DOM結構儘量簡潔,層次少,另外不要再DOM節點中運算.
  •     table這種佈局省事是省事,不過典型的牽一髮而動全身,改一個地方其餘都要變,因此儘可能不要用.
  •     JS的性能浪費的不是在代碼自己的執行,而是對DOM和CSS的操做.

    受能力所限,寫的可能有不對的地方還請諒解,歡迎你們留言討論.

相關文章
相關標籤/搜索