⤴Top⤴

加载阻塞

博客分类: 前端

加载阻塞

加载阻塞

CSS阻塞

CSS 属于 render blocking resource,无论外链或内联,都会阻塞渲染树的渲染。一般情况下,CSS 会延迟脚本执行和 DOMContentLoaded 事件。

<body>
  <h1>Tate</h1>
  <script>
    function print(){
      console.log('first print', document.querySelectorAll('h1'));
    }
    print();
    setTimeout(print);
  </script>
  <!-- 外链 -->
  <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <h1>Snow</h1>
  <!-- 内联 -->
  <script> console.log('second print'); </script>
  <style> h1{color: orange;} </style>
</body>

当注释掉 CSS 外链时,打印顺序为

first print NodeList [h1]
// 页面出现 h1 标签内容,即渲染完成
second print
first print NodeList(2) [h1, h1] // 异步

当加载 CSS 样式文件时,此时通过 Chrome Network 调试工具勾选 “Disabled cache”,再设置 “Throtting” 来模拟缓慢网络下的加载过程。打印顺序为

first print NodeList [h1]
first print NodeList(2) [h1, h1]
// ---------------加载 CSS 文件中,延迟---------------
// 页面出现 h1 标签内容,即渲染完成
second print

因此可看出

利用媒体类型和查询来解除 CSS 对渲染的阻塞,详见上一节页面渲染

JS阻塞

阻塞 DOM 解析

<body>
  <h1>Tate</h1>
  <script>
    function print(){
      console.log('first print', document.querySelectorAll('h1'));
    }
    print();
    setTimeout(print);
  </script>
  <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
  <h1>Snow</h1>
  <script> console.log('second print'); </script>
  <style> h1{color: orange;} </style>
</body>

打印顺序为

first print NodeList [h1]
first print NodeList [h1]
// 页面出现 'Tate'
// ---------------加载和执行 JS 文件中,延迟---------------
// 页面出现 'Snow'
second print

因此可看出

script

样式表、图片等资源文件的下载不会暂停 DOM 解析。浏览器会并行地下载这些文件,但通常会限制并发下载数。

延迟脚本 defer

立即下载,但脚本会延迟到整个页面都解析完毕后再运行。

<!-- 只适用于外链 -->
<script defer src="script.js">
<!-- 内联无效 -->
<script defer> console.log('defer'); </script>

script-defer

异步脚本 async

立即下载,期间不会阻塞 DOM 解析,等下载完成并执行时,才会阻塞解析。

<!-- 只适用于外链 -->
<script async src="script.js">
<!-- 内联无效 -->
<script async> console.log('async'); </script>

script-async

延迟和异步脚本一定会在 load 事件前执行,但可能在 DOMContentLoaded 事件触发之前或之后执行。

延迟脚本最终还是按照 js 顺序加载;异步脚本最终执行顺序不定。

动态插入

参考异步脚本载入提高页面性能一文的摘要:

<body>
  <h1>Tate</h1>
  <script>
    function print(){
        console.log('first print', document.querySelectorAll('h1'));
    }
    print();
    setTimeout(print);
  </script>
  <!-- 动态插入外链样式,异步执行,不阻塞 DOM 解析和渲染 -->
  <script>
    var doc = document;
    var bootcss = doc.createElement('link');
    bootcss.rel = 'stylesheet';
    bootcss.href = 'https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css';

    var tate = doc.getElementById('tate');
    doc.body.insertBefore(bootcss, tate);
  </script>
  <h1 id="tate">Snow</h1>
  <script> console.log('second print'); </script>
</body>

参考链接

  1. Google - 使用 JavaScript 添加交互 By Ilya Grigorik
  2. Asynchronous vs Deferred JavaScript By Ire Aderinokun
  3. CSS/JS 对 DOM 渲染的影响 By harttle
  4. 异步渲染的下载和阻塞行为 By harttle