CSS&JS阻塞
浏览器的渲染步骤
在了解JS&CSS阻塞前,我们需要知道浏览器渲染页面的步骤是什么?
- 浏览器根据HTML文件构建HTML树(DOM)
- 根据CSS文件构建CSS树(CSSOM)
- 将DOM和CSSOM合并成 render tree
- 计算Layout布局(文档流、盒模型、大小、位置)
- Paint绘制CSS的外观属性
- Compose合成,展示最终画面
CSS阻塞
CSS会阻塞页面的渲染。
根据上面浏览器渲染页面的步骤,我们知道 render tree 的合成需要 DOM tree 和 CSSOM tree。所以CSS会阻塞页面的渲染,但是并不会阻塞DOM的解析,因为页面渲染 DOM tree 也是必须的。
当存在CSS阻塞的情况时,浏览器会延迟JavaScript的执行,但仍然会加载JavaScript的资源。
JS阻塞
JavaScript能够读取并修改 DOM 和 CSSOM 属性。
当浏览器在解析DOM时,如果遇到了一个<srcipt>
标签,会停止DOM的构建,直至JavaScript文件执行完毕。
所以<srcipt>
的位置显得尤为重要,错误的<srcipt>
位置会导致严重的JS阻塞。
解决方法
由于存在CSS阻塞的情况时,浏览器会延迟JavaScript的执行,同时JavaScript能够读取并修改 DOM 和 CSSOM 属性,所以我们要提高CSS资源的优先级。
而且因为JavaScript的执行会停止DOM的构建,所以<srcipt>
标签的位置最好在最后面。
同时可以使用 <srcipt>
标签的 defer async 属性来异步加载JavaScript文件。
defer & async
defer:延迟脚本
- 语法:
<srcipt src='xxx' defer>
- defer必须使用在有src属性的
<srcipt>
标签上,即外联脚本。 - 异步加载和解析JS文件
- defer的作用更像是把
<srcipt>
标签放到<body>
标签的最后面。
async:异步脚本
- 语法:
<srcipt src='xxx' async>
- async属性也只能作用于外联脚本。
- 异步加载JS文件,并在合适的时候执行,一定在window.load前执行。
defer V.S async
- 都是异步加载JS文件
- async脚本的执行会在渲染和绘制(DOMContentLoaded)之后开始执行和求值;而defer脚本执行之后才会执行DOMContentLoaded。