轻松明白 CSS 和 JS 对页面渲染的阻塞

2,098 阅读2分钟

前言

前面有分析过页面的渲染逻辑(老生常谈之从输入URL到页面呈现的过程(全)),从上至下解析 HTML,构建 DOM 树和 Style Rules,其中构建 DOM 和解析 Style 是并行的,之后 DOM 树和 Style Rules 结合成 Render Tree。

下面我们来分析分析 CSS 和 JS 对 HTML 解析(DOM,Style Rules,Render Tree)的阻塞性

运行以下 Demo 的时候需要将浏览器控制台的网络先设置为 Slow 3G

CSS 的阻塞性

  1. 不阻塞 DOM 树的解析,但会阻塞 Style Rules 的解析,进而阻塞 Render Tree (因为渲染树需要等待 Style Rules,减少不必要的回流重绘)
<!DOCTYPE html>
<html>
<head>
  <script>
    setTimeout(() => {
      console.log(document.getElementById('app'))
    })
  </script>
  <link href="https://cdn.bootcdn.net/ajax/libs/animate.css/4.1.1/animate.compat.css" rel="stylesheet">
</head>
<body>
  <div id="app">
    666
  </div>
</body>
</html>
  1. 阻塞在 CSS 之后的 JS 的解析执行(因为某些 JS API 如 getComputedStyle 需要最新的样式数据)
<!DOCTYPE html>
<html>
<head>
  <link href="https://cdn.bootcdn.net/ajax/libs/animate.css/4.1.1/animate.compat.css" rel="stylesheet">
  <script>
    console.log(1)
  </script>
</head>
<body>
  <div id="app">
    666
  </div>
</body>
</html>

JS 的阻塞性

  1. JS 会阻塞在其后的 DOM 树的构建,进而影响 Render Tree。(因为 JS 经常操作 DOM API,为确保 DOM 一致性)。
<!DOCTYPE html>
<html>
<head>
</head>
<body>
  <div id="app1">
    333
  </div>
  <script>
    console.log(document.getElementById('app1'))
    console.log(document.getElementById('app2'))
  </script>
  <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.20/lodash.js"></script>
  <div id="app2">
    555
  </div>
</body>
</html>

异步脚本的阻塞性

前面我们其实说的是同步脚本的阻塞性,下面来看看异步脚本的阻塞性

从网上找的这幅图描述的相当的一目了然

  1. script

立即下载执行,下载执行的过程中阻塞 HTML 解析(DOM 构建)

  1. async script

立即下载执行,但是下载过程不影响 HTML 解析(DOM 构建)(也就不影响渲染),仅在执行过程阻塞 HTML 解析(DOM 构建)

执行不按顺序

  1. defer script

立即下载,延迟执行(HTML 解析完成后),不阻塞 HTML 的解析(DOM 构建)((也就不影响渲染)

执行按顺序

总结

知道了 CSS 与 JS 的阻塞性及其阻塞背后的设计思想,有助于提升自己对页面渲染流程的认知,并且可以给页面的性能优化提供思路,知其然知其所以然,一起加油。

参考


欢迎来前端菜鸟群一起摸鱼划水~516913974