js、css的阻塞問題


js、css的阻塞問題

  這篇文章主要是探索js、css的加載順序及其影響問題。

  下面的代碼可以讓瀏覽器阻塞:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>阻塞代碼</title>
</head>
<body>
  <script>
    // 阻塞代碼,參數單位s
    function blocking(blockingTime) {
      function getTime() {
        return new Date().getTime();
      }
      var startTime = getTime();
      // getTime()得到的時間單位是ms,所以乘1000
      while (getTime() < startTime + blockingTime*1000);
    }
    blocking(5);
  </script>
  <h3>hello</h3>
</body>
</html>

 

 

測試一:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>JS/css</title>
  <script>var start = +new Date;</script>
  <script>
    var end = +new Date;
    console.log(end-start);
  </script>
  <link href="http://udacity-crp.herokuapp.com/style.css?rtt=2" rel="stylesheet">
</head>  

<body>
</body>

</html>

注:其中的+為單目運算符,可以將對象轉化為數字。

顯然,在控制台輸出的結果為0。因為上面的js語句剛剛執行完,就執行下面的語句,所以時間間隔幾乎為0。

 

 

測試二:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>JS/css</title>
  <script>var start = +new Date;</script>
  <link href="http://udacity-crp.herokuapp.com/style.css?rtt=2" rel="stylesheet">
  <script>
    var end = +new Date;
    console.log(end-start);
  </script>
</head>  

<body>
</body>

</html>

 

這個測試中,我將css置於兩個script之間,最后的輸出結果為2870, 當然這個值是個隨機數,一定是遠遠大於0的。

然后我們在打開開發者工具的Network的情況下點擊刷新,這時再看console控制台打印出的值為2967, 然后我們觀察加載css所需的時間:

2.97s,也就是2967ms。

結論: 外部樣式的加載會阻塞在它之后的<script>語句的加載,並且<script>是在<link>完全加載結束之后執行的。

 

  

 

 

測試3:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS/CSS</title>

  <script>var start = +new Date;</script>
  <link href="http://udacity-crp.herokuapp.com/style.css?rtt=2" rel="stylesheet">
  <script>
    var endAfterCss = +new Date;
    console.log("css", (endAfterCss - start));
  </script>

</head>
<body>
  
  <script src="http://udacity-crp.herokuapp.com/time.js?rtt=1&a"></script>

  <div id="result"></div>
  
  <script>
    var endAfterScript = +new Date;
    console.log("js",(endAfterScript - start));
  </script>
  
</body>
</html>

在console控制台的輸出如下:

我們可以看到在兩者之間還有一個外部的script標簽,為什么兩者的執行卻是幾乎同時發生的呢?

  我們同樣在network中刷新,然后得到的console控制台信息如下:

    然后查看network,並查看外部css的詳情, 如下所示:

 可以看出,css的加載時間就是3.12s,然后它的加載阻塞了下面的script的執行,css一旦加載完畢,下面的script立即執行,所以得到了3118這個值。這個很容易理解。

 注意觀察上圖,可以發現外部css和外部js的加載時間幾乎是同時的,也就是說外部css的加載不會影響到下面的js的加載。

但是為什么在外部js文件下面的js卻是3130呢? 外部的script的加載不是也需要一定的時間嗎?我們看看js的加載時間。

 我們可以看到,外部js的加載時間僅為1.38s,也就是說在外部css還沒有加載完的時候js就加載結束了,但是它並沒有執行,而是等到css加載完了之后才執行的。所以才會得到3130這個數值。其中的差值就是js執行的時間。

 

結論: 在css加載的過程中,下面的外部js同時也會加載,只是下面的外部js必須等到上面的css加載完成之后才能執行。 並且js會阻斷下面的js的執行,因為js的執行是單線程的,所以在外部css執行結束之后,下面的內聯css才會繼續執行。

 

 

 

測試4:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS/CSS</title>

  <script>var start = +new Date;</script>
  <link href="http://udacity-crp.herokuapp.com/style.css?rtt=2" rel="stylesheet">
  <link rel="stylesheet" href="https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/mancard/css/card_min_dee38e45.css">
  <script>
    var endAfterCss = +new Date;
    console.log("css", (endAfterCss - start));
  </script>

</head>
<body>
  
  <script src="http://udacity-crp.herokuapp.com/time.js?rtt=1&a"></script>

  <div id="result"></div>
  
  <script>
    var endAfterScript = +new Date;
    console.log("js",(endAfterScript - start));
  </script>
  
</body>
</html>

network如下:

即頁面中的兩個css是同時加載的,並且js也是,即兩個css和js都是同時加載的,我的第二個css在html中是在js上面的,但是這里顯示js卻是先加載的,也就是說第一個css加載的時候,后面的js和css是同時加載的,至於誰最先加載,就不好說了,看下圖,在代碼沒有改變的情況下,js是最后加載的。

說明:黃色部分為 Initial Connection ,即初始鏈接網絡所消耗的時間,這種情況的發生往往是因為多個請求導致的

如果我將耗時較長的css刪除,那么我們得到的瀑布流如下所示:

可以看到這里確是js先加載的!

console控制台輸出的結果是:

所以說link的加載不會影響js的加載是完全正確的。

 

結論:  如果同時具有兩個link,一個外部的css,那么此三者是同時加載的,只是無法確定后面兩者的先后關系。同樣的,必須要在css加載結束之后js才能執行。

    如果只有一個css、一個js,那么兩者的加載順序是不確定的。

 

 

 

測試5:

  異步加載js

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
  <script>var start = +new Date;</script>
  <link href="http://udacity-crp.herokuapp.com/style.css?rtt=2" rel="stylesheet">
  
</head>
  
<body>
  test
  <script src="http://udacity-crp.herokuapp.com/time.js?rtt=1&a" async></script>
  <div id="result"></div>
  <script>
    var end = +new Date;
    console.log(end - start);
  </script>
  
</body>
</html>

  表現如下:

  可以看出,css的加載時間為2.37s, 在控制台的輸出時間為2368ms,也就是說在css執行完成之后,外部js並沒有阻礙下面的內聯js的執行,而在頁面中我們可以看到2094.6450000,這是指外聯js執行的時間,我們在console控制台中可以看到外聯js的執行時間為2.07s,也就是說在外聯js加載完成之后就立即執行了,而沒有等待外聯css加載完畢再執行。

  說明:再外聯js的代碼中我們使用了window.performance.now()方法,這個方法返回的是頁面開啟后的時間,且其單位為ms, 小數點之后保留了13位,這樣的好處是較之於Data.now()更有利於我們檢測性能。

  更多關於window.performance.now()的內容可以參照這篇文章:http://www.cnblogs.com/xiaohuochai/archive/2017/03/09/6523397.html

 

結論: 使用了async屬性之后,就可以實現js的異步加載,即該文件的執行不必等待外聯css文件加載完成就可以執行,並且也不會阻塞后面的js的加載。

 

 

 

 

測試6:

  創建<script>元素實現加載外部js

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
  <script>var start = +new Date;</script>
  <link href="http://udacity-crp.herokuapp.com/style.css?rtt=2" rel="stylesheet">
  
</head>
  
<body>
  test
  <script> 
    var script = document.createElement('script');
    script.src = "http://udacity-crp.herokuapp.com/time.js?rtt=1&a";
    document.getElementsByTagName('head')[0].appendChild(script);
  </script>
  <div id="result"></div>
  <script>var end = +new Date;document.getElementById("result").innerHTML = end-start;</script>
  
</body>
</html>

 

   我們可以看到瀑布流如下所示:

  也就是說,在這種情況下,只有css完全加載完成之后,js才會加載。

 

結論:  在script標簽是動態創建的情況下,其加載的優先級較低,會在css完全加載之后再加載。 注意觀察: js的優先級為Low,所以會在css完全加載結束之后加載。

因為動態創建標簽也是js語句,之前降到了語句的執行會被css阻塞。

 

 

 

測試7:

 

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
  <script>var start = +new Date;</script>
  <link href="http://udacity-crp.herokuapp.com/style.css?rtt=2" rel="stylesheet">
  <script>
  var end0 = +new Date;
  console.log(end0 - start);
  </script>
  
</head>
  
<body>
   <script src="http://udacity-crp.herokuapp.com/time.js?rtt=1&a"></script>
  <div id="result"></div>
  <script>
  var end1 = +new Date;
  console.log(end1 - start);
  </script>

  <script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>
  <script>
  var end2 = +new Date;
  console.log(end2 - start);
  </script>
  
</body>
</html>

 

輸出如下所示:

 

瀑布流如下所示:

可以看出css加載的過程中,后面的兩個js同時加載,且加載的速度比css要快,這時css阻塞着后面的加載,一旦css加載完畢,已經加載好的js立即執行。

 

 

 

 

 

 

 

 

參考文章:http://www.cnblogs.com/shinnyChen/p/3762704.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM