CSSOM:一旦浏览器接收到所有的 CSS,它会生成一个 CSS 中包含的标签和类的树模型,称为 CSS 对象模型,在树节点上还附有样式信息。这棵树描述了页面内容是如何设置样式的。
渲染树:通过组合 DOM 和 CSSOM,浏览器构造一个渲染树,它包含页面内容以及要应用的样式信息。
布局:布局这一步计算屏幕上页面内容的实际位置和大小。
绘制:最后一步使用布局信息将实际像素绘制到屏幕上。
单个步骤是相当简单的,使事情变得困难并限制性能的是这些步骤之间的依赖。DOM 和 CSSOM 的构造通常具有最大的性能影响。
这个图表显示了关键呈现路径的步骤,里面包括等待依赖,如箭头所示。
关系呈现路径中重要的依赖
在加载 CSS 和构造完整的 CSSOM 之前,什么都不能显示给客户端。因此 CSS 被称为是阻塞渲染的。
JavaScript(JS)更糟糕,因为它可以访问和更改 DOM 和 CSSOM。 这意味着一旦发现 HTML 中的脚本标记,DOM 构造就会被暂停,并从服务器请求脚本。一旦脚本被加载,只有在所有 CSS 被提取和 CSSOM 被构造以后,它才能被执行。在 CSSOM 构建之后 JS 被执行,在下面的例子中,它可以访问和改变 DOM 以及 CSSOM。只有这样之后,DOM的构造才能进行,并且页面才能显示给客户端。因此 JavaScript 被称为是阻塞解析的。
JavaScript 访问 CSSOM 和更改 DOM 的示例:
<script> ... var old = elem.style.width; elem.style.width = "50px"; document.write("alter DOM"); ... </script>JS 甚至会影响更恶劣。例如 jQuery 插件 访问计算后的 HTML 元素的布局信息,然后开始一次又一次地改变 CSSOM,直到实现了所需的布局。因此,在用户将看到白色屏幕以外的任何东西之前,浏览器必须一次又一次地重复地执行 JS、构造渲染树和布局。
有三个优化 CRP 的 基本概念:
减少关键资源: 关键资源是页面最初渲染时所需的资源(HTML,CSS,JS 文件)。通过将渲染不滚动时可见的网站部分(称为首屏)所需要的 CSS 和 JS 内联可以大大减少关键资源。接下来的 JS 和 CSS 应该被异步加载。无法被异步加载的文件可以拼接到一个文件中。
最小化字节: 通过最小化和压缩 CSS,JS 和图像,可以大大减少 CRP 中加载的字节数。
缩短 CRP 长度: CRP 长度是获取所有关键资源所需的与服务器之间的最大连续往返数。它可以通过减少关键资源和最小化它们的大小(大文件需要多个往返来获取)来缩短。将 CSS 放在 HTML 顶部,以及 JS 放在 HTML 底部,可以进一步地缩短它的长度,因为 JS 执行总是会阻塞对 CSS 的抓取、对 CSSOM 和 DOM 的构造。
此外,浏览器缓存 是非常有效的,应该在所有的项目中加以使用。它对于这三个优化项都很合适,因为缓存的资源不必先从服务器加载。
CRP 优化的整个主题是相当复杂的,特别是内联、级联和异步加载,它们可能会破坏代码的可重用性。幸运的是,有很多强大的工具,可以为你做好这些优化,这些工具可以被集成到你的构建和部署链里。你的确应该地看看下面的工具……
分析: GTmetrix 用来衡量网页速度,webpagetest 用来分析你的资源,以及 Google 的PageSpeed Insights,为你的网站生成有关如何优化 CRP 的提示。
内联和优化:[Critical]((https://github.com/addyosmani/critical) 非常适合自动将你的明显位置的 CSS 内联并且异步加载其余 CSS,processhtml 连接你的资源和 PostCSS 进一步优化 CSS。
最小化和压缩: 我们使用 tiny png 来进行图像压缩,UglifyJs 和 cssmin 来进行最小化,Google Closure 来进行 JS 优化。
有了这些工具只需很小的工作量,你就可以打造一个前端性能极好的网站。这里是 Thinks 商城第一次访问时的页面速度测试:
thinks.com 的 Google 网页速度分数
有趣的是,PageSpeed Insights 内部唯一的抱怨是,Google 分析的脚本缓存生命周期太短。所以 Google 基本上在抱怨它自己。