译-解密关键渲染路径
栏目: JavaScript · 发布时间: 5年前
内容简介:就像steve在之前发布的文章中指出的那样,window.onload并不是最好的用来衡量网站性能指标的方式。它是一个很方便的,经常被使用的一个指标,但是并不能明确的捕获现代浏览器页面的动态特性。相反,我们需要考虑用户对于页面性能的感知:如何让用户更快的与页面进行交互?交互的定义完全取决页面的不同而不同。对于一些页面,只需要在页面显示文本即可,用户能够在页面浏览他们请求的信息。对于有些页面,有可能需要请求许多js组件去安装JavaScript UI,例如Gmail。无论如何,上面两种情况,用户都需要能够看到
就像steve在之前发布的文章中指出的那样,window.onload并不是最好的用来衡量网站性能指标的方式。它是一个很方便的,经常被使用的一个指标,但是并不能明确的捕获现代浏览器页面的动态特性。相反,我们需要考虑用户对于页面性能的感知:如何让用户更快的与页面进行交互?
交互的定义完全取决页面的不同而不同。对于一些页面,只需要在页面显示文本即可,用户能够在页面浏览他们请求的信息。对于有些页面,有可能需要请求许多js组件去安装JavaScript UI,例如Gmail。无论如何,上面两种情况,用户都需要能够看到页面上显示信息,也就是说,浏览器需要在屏幕上渲染一些东西。
所以,考虑到这一点,需要考虑的问题是,用户请求到现代浏览器首次呈现内容都发生了什么?
DOM + CSSOM = Render Tree
渲染的具体时间和行为,取决于页面解析、布局以及浏览器合成管道(?)。然而,撇开具体的实现差异,在页面上显示任何内容,所有浏览器都需要构建渲染树(rendering tree)。
解析HTML文档去构建DOM。同时,还有一个经常被遗忘的表亲,CSSOM,它是通过指定的样式表和资源构建的(内联样式表,外联样式表等)。然后,使用DOM和CSSOM构建渲染树,此时浏览才有足够的信息在屏幕上进行布局和绘制(layout and paint)内容。目前为止,一切顺利。
然而,上面的图表表示的是最乐观的情况:CSSDOM和DOM是并行构建的。然后,不幸的是,我们还需要了解我们最喜欢的朋友与敌人--javascript。
- DOM树构建操作遇到同步js脚本就会被阻塞。因为,同步JavaScript可以随时发出document.write操作。
- js可以查询dom对象的计算样式,意味着js脚本的也会被css阻塞(查询dom对象的计算样式需要CSSOM)
与前面DOM和CSSOM并行构建相比,这两个构建操作都受到了js的影响:DOM构建只有等js脚本执行完毕之后才会继续,而js操作必须等CSSOM可用时才可以继续。
上述问题如何解决,取决于页面中资源的位置以及资源数量,页面首次渲染元素的时间也会随之发生改变。我们可以获取度量标准或者监控这个过程吗?事实证明,当然可以!
Document Interactive 和DOMContentLoaded
HTML5规范定义了一系列文档良好的步骤序列,用户代理在构建页面的时候必须遵循这些步骤。具体说,end序列捕获了两种状态,可以帮助回答我们前面的问题。
- 当用户代理停止解析文档时,文档被标记为“interactive”。意味着DOM树构建完成。
- 一旦带有“defer”属性的脚本被执行,并且没有任何样式阻塞脚本,用户代理就会触发DOMContentLoaded(DCL)事件。意味着,CSSOM准备完成(?)。
如果没有同步js脚本,DOM和CSSOM会被并行构建。一旦引入js,事件就变得更加有趣了。
如果添加带有“defer”属性的js脚本,就解除了DOM树构建的阻塞,文档交互状态不需要等待js的执行。然而,在DOMContentLoaded事件被触发之前这个脚本会被执行。进一步,js可能会查询CSSOM,DOMContentLoaded可能会被阻止直到CSSOM完成才会继续执行。简言之,defer脚本解除了文档交互状态的阻塞,但是依然有可能阻塞DOMContentLoaded。(defer脚本会在遇到