轉載自http://www.cnblogs.com/yuezk/archive/2013/01/11/2855698.html javascript
最近在學習前端的性能優化,有必要了解一下頁面的渲染流程,以便對症下藥,找出性能的瓶頸所在。如下是我看到的一些東西,分享給你們。 css
參考:Understanding the renderer html
頁面的渲染有如下特色: 前端
具體來講: java
當咱們從網絡上獲得HTML的相應字節時,DOM樹就開始構建了。由瀏覽器更新UI的線程負責。當遇到如下狀況時,DOM樹的構建會被阻塞: 瀏覽器
渲染樹構建自DOM樹,而且會被樣式文件阻塞。 緩存
因爲是基於單線程的事件輪詢,即便沒有腳本和樣式的阻塞,當這些腳本或樣式被解析、執行而且應用的時候,也會阻塞頁面的渲染。 性能優化
一些不會阻塞頁面渲染的狀況: 網絡
下面,經過一個例子來講明一下(完整的代碼): app
1 <html> 2 <body> 3 <link rel="stylesheet" href="example.css"> 4 <div>Hi there!</div> 5 <script> 6 document.write('<script src="other.js"></scr' + 'ipt>'); 7 </script> 8 <div>Hi again!</div> 9 <script src="last.js"></script> 10 </body> 11 </html>
代碼很容易看明白,若是放在瀏覽器中打開會當即顯示出想要的頁面。下面,讓咱們用慢鏡頭回放的方式來看看它到底是怎麼渲染的。
1 <html> 2 <body> 3 <link rel="stylesheet" href="example.css"> 4 <div>Hi there!</div> 5 <script>...
首先,解析器遇到了example.css,並將它從網絡中下載下來。下載樣式表的過程是耗時的,可是解析器並無被阻塞,繼續往下解析。接下來,解析器遇到script標籤,可是因爲樣式文件沒有加載下來,阻塞了該腳本的執行。解析器被阻塞住,不能繼續往下解析。
渲染樹也會被樣式文件阻塞,因此這時候沒有瀏覽器不會去渲染頁面,換句話說,若是example.css文件下載不下來,Hi there! 是顯示不出來的。
接下來,繼續。。。
<html> <body> <link rel="stylesheet" href="example.css"> <div>Hi there!</div> <script> document.write('<script src="other.js"></scr' + 'ipt>'); </script>
一旦example.css文件加載完成,渲染樹也就被構建好了。
內聯的腳本執行完以後,解析器就會當即被other.js阻塞住。一旦解析器被阻塞,瀏覽器就會收到繪製請求,"Hi there!"也就顯示在了頁面上。
當other.js加載完成以後,解析器繼續向下解析。。。
1 <html> 2 <body> 3 <link rel="stylesheet" href="example.css"> 4 <div>Hi there!</div> 5 <script> 6 document.write('<script src="other.js"></scr' + 'ipt>'); 7 </script> 8 <div>Hi again!</div> 9 <script src="last.js"></script>
解析器遇到last.js以後會被阻塞,而後瀏覽器收到了另外一個繪製請求,"Hi again!"就顯示在了頁面上。最後last.js會被加載,而且會被執行。
可是,爲了減緩渲染被阻塞的狀況,現代的瀏覽器都使用了猜想預加載(speculative loading)。
在上面這種狀況下,腳本和樣式文件會嚴重阻塞頁面的渲染。猜想預加載的目的就是減小這種阻塞時間。當渲染被阻塞的時候,它會作如下一些事:
可是,猜想預加載不能發現經過javascript腳原本加載的資源文件(如,document.write())。
注:全部的「現代」瀏覽器都支持這種方式。
回過來再看上面的例子,經過猜想預加載這種方式是怎麼工做的。
1 <html> 2 <body> 3 <link rel="stylesheet" href="example.css"> 4 <div>Hi there!</div> 5 <script>...
解析器返現了example.css,並從網絡獲取,解析器沒有被阻塞,繼續解析,當遇到了內聯的script節點時,被阻塞住,因爲樣式文件沒有 加載完成,阻塞了腳本的執行。渲染樹一樣也被樣式文件阻塞住,因此瀏覽器沒有收到渲染請求,看不到任何東西。到目前爲止,和剛纔提到的那種方式是同樣的。 可是接下來就由變化了。
預加載器(Speculative loader)繼續「閱讀」文檔,發現了last.js並視圖加載它。接下來:
1 <html> 2 <body> 3 <link rel="stylesheet" href="example.css"> 4 <div>Hi there!</div> 5 <script> 6 document.write('<script src="other.js"></scr' + 'ipt>'); 7 </script>
一旦example.css文件加載完成,渲染樹也就完成了構建,內聯的腳本也能夠執行,以後解析器又被other.js阻塞住。解析器被阻塞住以後,瀏覽器會收到第一個渲染請求,「Hi there!」 會被現實在頁面上。這個步驟和剛纔那種狀況是一致的。而後:
1 <html> 2 <body> 3 <link rel="stylesheet" href="example.css"> 4 <div>Hi there!</div> 5 <script> 6 document.write('<script src="other.js"></scr' + 'ipt>'); 7 </script> 8 <div>Hi again!</div> 9 <script src="last.js"></script>
解析器發現了last.js,可是因爲預加載器剛纔已經把它給加載下來了,放在了瀏覽器的緩存裏,因此last.js會被當即執行。以後,瀏覽器會收到渲染請求「Hi again」也被顯示在了頁面上。
經過先後兩種狀況的對比,但願你們能夠對頁面的渲染有必定的瞭解,而後再有針對性的作一些優化。晚安!