在解析DOM的过程中,如果遇到了javascript
脚本,那么需要先暂停DOM解析去执行javascript
,因为JavaScript有可能会修改当前状态下的DOM.
不过在执行JavaScript脚本之前,如果页面中包含了外部CSS文件的引用,或者通过style标签内置了CSS内容,那么渲染引擎还需要将这些内容转换为CSSOM,因为JavaScript有修改CSSOM的能力,所以在执行JavaScript之前,还需要依赖CSSOM。也就是说CSS在部分情况下也会阻塞DOM的生成。
渲染流水线:CSS文件下载完成并生成CSSOM => 执行JavaScript脚本 => 继续构建DOM => 构建布局树 => 绘制页面
从发起URL请求开始,到首次显示页面的内容,在视觉上会经历三个阶段:
- 第一阶段,等请求发出去之后,到提交数据阶段,这时页面展示出来的还是之前页面的内容
- 第二阶段,提交数据之后渲染进程会创建一个空白页面,我们通常把这段时间称为解析白屏,并等待CSS文件和JavaScript文件的加载完成,生成CSSOM和DOM,然后合成布局树,最后还要经过一系列的步骤准备首次渲染。
- 第三阶段,等首次渲染完成之后,就开始进入完整页面的生成阶段,然后页面会一点点被绘制出来。
针对第二阶段,这个阶段的主要问题是白屏时间,如果白屏时间过久,就会影响到用户体验,为了缩短白屏时间,我们来挨个分析这个阶段的主要任务,包括了解析HTML、下载CSS、下载JavaScript、生成CSSOM、执行JavaScript、生成布局树、绘制页面一系列操作。
通常情况下的瓶颈主要体现在下载CSS文件、下载JavaScript文件和执行JavaScript。
所以想缩短白屏时间,可以有以下策略:
- 通过内联JavaScript、内联CSS来移出这两种类型的文件下载,这样获取到HTML文件之后就可以直接开始渲染流程了。
- 但并不是所有的场合都适合内联,那么还可以尽量减少文件大小,比如通过webpack等工具移除一些不必要的注释,并压缩JavaScript文件。
- 还可以将一些不需要在解析HTML阶段使用的JavaScript标记上sync或者defer。
- 对于大的CSS文件,可以通过媒体查询属性,将其拆分为多个不同用途的CSS文件,这样只有在特定的场景下才会加载特定的CSS文件。