HTML執行順序-一探究竟

瞭解瀏覽器線程基礎

一個頁面的呈現主要是由瀏覽器渲染進程實現的(render進程),主要做用爲頁面的渲染,腳本執行,事件處理等。而render進程是多線程的,它主要包含如下主要線程:javascript

1 GUI渲染線程css

  • 負責渲染瀏覽器界面,解析HTML,CSS,構建DOM樹和RenderObject樹,佈局和繪製等。
  • 當界面須要重繪(Repaint)或因爲某種操做引起迴流(reflow)時,該線程就會執行
  • 注意,GUI渲染線程與JS引擎線程是互斥的,當JS引擎執行時GUI線程會被掛起(至關於被凍 結了),GUI更新會被保存在一個隊列中等到JS引擎空閒時當即被執行。

2 JS引擎線程html

  • 也稱爲JS內核,負責處理Javascript腳本程序。(例如V8引擎)
  • JS引擎線程負責解析Javascript腳本,運行代碼。
  • JS引擎一直等待着任務隊列中任務的到來,而後加以處理,一個Tab頁(renderer進程)中 不管何時都只有一個JS線程在運行JS程序
  • 一樣注意,GUI渲染線程與JS引擎線程是互斥的,因此若是JS執行的時間過長,這樣就會形成頁面的渲染不連貫,致使頁面渲染加載阻塞。

3 事件觸發線程java

  • 歸屬於瀏覽器而不是JS引擎,用來控制事件循環(能夠理解,JS引擎本身都忙不過來,須要瀏覽器另開線程協助)
  • 當JS引擎執行代碼塊如setTimeOut時(也可來自瀏覽器內核的其餘線程,如鼠標點擊、AJAX異步請求等),會將對應任務添加到事件線程中
  • 當對應的事件符合觸發條件被觸發時,該線程會把事件添加到待處理隊列的隊尾,等待JS引擎的處理
  • 注意,因爲JS的單線程關係,因此這些待處理隊列中的事件都得排隊等待JS引擎處理(當JS引擎空閒時纔會去執行)

4 定時觸發器線程node

  • 傳說中的setInterval與setTimeout所在線程
  • 瀏覽器定時計數器並非由JavaScript引擎計數的,(由於JavaScript引擎是單線程的, 若是處於阻塞線程狀態就會影響記計時的準確)
  • 所以經過單獨線程來計時並觸發定時(計時完畢後,添加到事件隊列中,等待JS引擎空閒後執行)

5 異步http請求線程jquery

  • 在XMLHttpRequest在鏈接後是經過瀏覽器新開一個線程請求
  • 將檢測到狀態變動時,若是設置有回調函數,異步線程就產生狀態變動事件,將這個回調再放入事件隊列中。再由JavaScript引擎執行。

JS阻塞特性

由上述GUI線程和JS引擎互斥的關係,咱們也就能更好的理解爲何JS運行會阻塞頁面的渲染,也就是常說的JS阻塞特性segmentfault

HTML總體執行步驟

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>等標籤時,就會下載相應的內容。

下載的角度講:

  • <link>標籤下載不會阻塞<script>標籤,由紅色①可看出;
  • <script>不會阻塞<script>標籤下載,由藍色②可看出;
  • <script>標籤也不會阻塞<link>標籤,但會阻止<img>標籤,由於在HTML文檔中,img標籤在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...

相關文章
相關標籤/搜索