翻译--解密关键渲染路径

 

就像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脚本会在遇到</html>标签时才执行,但是是在DOMContentLoaded事件之前)

如果添加带有“async”属性的脚本,会发生同defer类似的行为,唯一不同的是,DCL并不需要等待异步脚本的执行。(async脚本可能在DCL之前或者之后执行,但是会在load事件之前执行)

这里的第一个要点是,默认情况下,js脚本会阻塞DOM树的构建,并且js脚本可能会被CSSOM构建过程阻塞。使用同步脚本不好,但是你应该知道了这个事实。给脚本添加“defer”和“async”相当于对文档解析器做了不使用document.write的隐式承诺,也就是解除了对DOM树构建的阻塞。

第二个要点是,如果任何时候我们需要等待js的执行,那么我们必须等待CSSOM构建完成。换句话说,js和css之间存在严重的依赖性。样式表放在头部,脚本放在尾部,现在你知道为什么了吗。

OK。这些都是很好的理论知识,但是这些知识可以帮助我们优化页面吗?这两个指标都不能直接指出何时绘制页面,但是监控其中之一或者两个都是朝着我们提高感知性能的最终目标的正确方面迈出的一步。

 跟踪页面的关键路径

如果没有其他情况,监控“文档交互”(document interactive)能够给你一个很好的指标,用来判断DOM树的构建是否受到了同步脚本的影响。有时候,这种行为无法避免,但是我们需要知道这个原理和事实,而不是简单的理解为“它就是这样工作的”。

DOMContentLoaded事件是一个重要的里程碑。在很多流行库中,例如jQuery,一旦事件被触发,就会开始执行代码。换句话说,这可能是客户端代码与页面交互的第一个点,并向用户提供有意义的反馈。如果编码正确,通过渐进增强方式,可以首先得到页面的骨架,用户可以开始于页面交互的同时,页面处理剩余的工作。IE团队有一个很好的例子用来说明DOMContentLoaded和window.onload事件之间的差别。(访问不了呢,该死的墙)

DOMContentLoaded事件何时触发?

 你可以测量的东西,你才可以优化。更好的选择,Navigation timing帮助我们捕获了所有我们需要的事件:domInteractive,domContentLoadedEvent{start,end},以及loadEvent{start,end}。如果你已经准备好追踪onload事件,你可能还需要添加两个我们提过的两个事件。

在这一点上,如果你使用Google Analutics,将近圣诞节时。该团队最近添加了DOM timing功能,你能猜到它追踪的是什么吗?是的

登录您的GA帐户,并前往“内容>网站速度”。完成后,转到“Performance”选项卡查看所有页面的时间直方图,或者深入到特定页面的统计信息中。从那里,您可以跟踪文档交互、DCL和onload事件

 只是为了好玩,这里是一个并排比较的DCL和onload直方图为我的网站

 

到DCL的中位时间小于1s,而onload的中位时间为~1.5s。相对较高的DCL计时立即告诉我,可能有一个脚本阻塞了DOM的构建——我应该重新考虑这个问题。尽管如此,DCL和onload之间存在约0.5s的增量,这一事实告诉我,我并没有强迫用户在看到某些内容之前等待下载所有资产。

 

原文地址:

the critical render path

performance网站

 

posted @ 2019-05-05 00:42  Jamie0327  阅读(182)  评论(0编辑  收藏  举报
levels of contents