一個頁面的呈現主要是由瀏覽器渲染進程實現的(render進程),主要做用爲頁面的渲染,腳本執行,事件處理等。而render進程是多線程的,它主要包含如下主要線程:javascript
1 GUI渲染線程css
2 JS引擎線程html
3 事件觸發線程java
4 定時觸發器線程node
5 異步http請求線程jquery
由上述GUI線程和JS引擎互斥的關係,咱們也就能更好的理解爲何JS運行會阻塞頁面的渲染,也就是常說的JS阻塞特性
。segmentfault
0.加載總體html文件瀏覽器
1.至上而下解析html 多線程
2.解析html創建dom樹,遇到諸如<script>、<link>等標籤時,就會去下載相應內容,並解
析、執行。若是是<link>標籤,解析css構建CSSOM樹app
4.DOM和CSSOM結合生成render樹
5.佈局render樹(Layout/reflow),負責各元素尺寸、位置的計算
6.繪製render樹(paint),繪製頁面像素信息
7.瀏覽器會將各層的信息發送給GPU,GPU會將各層合成(composite),顯示在屏幕上。
HTML解析過程是至上而下的,當html解析器遇到諸如<script>、<link>等標籤時,就會去下載相應內容。且加載、解析、執行JavaScript會阻止解析器往下執行,要強調 渲染
和 下載
是不衝突的,渲染是GUI線程在執行,下載是下載線程在執行,瀏覽器多線程。
如下爲實驗:
HTML代碼:
<!DOCTYPE html> <html lang="zh"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>淺談Html頁面內容執行順序</title> <link rel="stylesheet" href="red.css"> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript" src="test.js"></script> <link rel="stylesheet" href="font.css"> <script type="text/javascript" src="test2.js"></script> </head> <body> <p>html順序測試</p> <img src="1.png" alt=""> <input value="101" /> <link rel="stylesheet" href="styl.css"> </body> </html>
Test.js代碼:
for(var i=0;i<10000;i++){ console.log("delay"); if(i==9999){ loadStyle('lime.css'); } } function loadStyle(url){ var link = document.createElement('link'); link.type = 'text/css'; link.rel = 'stylesheet'; link.href = url; var head = document.getElementsByTagName('head')[0]; head.appendChild(link); }
Test2.js代碼:
console.log("after blocking script,you will appear");
從圖中能夠看出:遇到<script>、<link>等標籤時,就會下載相應的內容。
從下載
的角度講:
總結
下就是:當HTML解析器遇到<script>、<link>、<img>標籤,開始下載時,只存在一種阻塞狀況,就是<script>標籤會阻止<img>資源下載,其他<script>、<link>相互之間下載沒有影響。下載完成以後,就會運行解析相應的JS文件或者CSS文件,運行JS文件須要JS引擎線程,前面提到,JS引擎和GUI時互斥的,因此在 解析
的角度講,JS引擎運行,會阻塞GUI,即阻止頁面渲染。從上圖能夠看出,在test.js下載以後,解析運行時,因爲有for循環函數的運行,頁面首次渲染時間被推至1100ms才渲染完成。
HTML代碼
<!DOCTYPE html> <html> <head> <meta charset=utf-8 /> <meta name="robots" content="noindex"> <title>Hang test</title> <style> body { font-family: sans-serif; } </style> <script> console.log('doc state: ' + document.readyState); document.onreadystatechange = function () { console.log('doc state change: ' + document.readyState); }; </script> <link href="http://hang.nodester.com/hang.css?5000" rel="stylesheet" /> </head> <body> <p>Refresh with the console open to see the hanging</p> <script src="http://static.jsbin.com/js/render/edit.js?4.1.4" async></script> <script>jsbinShowEdit && jsbinShowEdit({"static":"http://static.jsbin.com","root":"http://jsbin.com"});</script> <script> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-1656750-34', 'auto'); ga('require', 'linkid', 'linkid.js'); ga('require', 'displayfeatures'); ga('send', 'pageview'); </script> </body> </html>
由https://blog.csdn.net/gbstack...,咱們能夠獲得:
由圖中能夠看出:
外部腳本與外部樣式是並行加載
(即在 下載
階段,<script>、<link>互不影響,符合上述結論),但直到外部樣式加載完畢,外部腳本纔開始執行(即外部樣式的下載,雖然不會影響外部腳本的下載,但會影響腳本的運行)
文章參考:
https://segmentfault.com/a/11...
http://www.cnblogs.com/dojo-l...