前言
前面有分析过页面的渲染逻辑(老生常谈之从输入URL到页面呈现的过程(全)),从上至下解析 HTML,构建 DOM 树和 Style Rules,其中构建 DOM 和解析 Style 是并行的,之后 DOM 树和 Style Rules 结合成 Render Tree。
下面我们来分析分析 CSS 和 JS 对 HTML 解析(DOM,Style Rules,Render Tree)的阻塞性
运行以下 Demo 的时候需要将浏览器控制台的网络先设置为
Slow 3G
CSS 的阻塞性
- 不阻塞 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> 复制代码
- 阻塞在 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 的阻塞性
- 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> 复制代码
异步脚本的阻塞性
前面我们其实说的是同步脚本的阻塞性,下面来看看异步脚本的阻塞性
从网上找的这幅图描述的相当的一目了然
- script
立即下载执行,下载执行的过程中阻塞 HTML 解析(DOM 构建)
- async script
立即下载执行,但是下载过程不影响 HTML 解析(DOM 构建)(也就不影响渲染),仅在执行过程阻塞 HTML 解析(DOM 构建)
执行不按顺序
- defer script
立即下载,延迟执行(HTML 解析完成后),不阻塞 HTML 的解析(DOM 构建)((也就不影响渲染)
执行按顺序
总结
知道了 CSS 与 JS 的阻塞性及其阻塞背后的设计思想,有助于提升自己对页面渲染流程的认知,并且可以给页面的性能优化提供思路,知其然知其所以然,一起加油。