优化网站性能和关键渲染路径
已发表: 2022-03-11您的网页的渲染性能是否符合当今的标准? 渲染是将服务器的响应翻译成用户访问网站时浏览器“绘制”的图片的过程。 糟糕的渲染性能可以转化为相对较高的跳出率。
有不同的服务器响应来确定是否呈现页面。 在本文中,我们将重点关注网页的初始渲染,它从解析 HTML 开始(前提是浏览器已成功接收到 HTML 作为服务器的响应)。 我们将探索可能导致高渲染时间的问题,以及如何解决它们。
关键渲染路径
关键渲染路径 (CRP) 是浏览器将代码转换为屏幕上可显示像素的过程。 它有几个阶段,其中一些可以并行执行以节省时间,但有些部分必须依次完成。 这里是可视化的:
首先,一旦浏览器得到响应,它就会开始解析它。 当它遇到依赖项时,它会尝试下载它。
如果它是一个样式表文件,浏览器必须在渲染页面之前完全解析它,这就是为什么CSS 被称为渲染阻塞的原因。
如果是脚本,浏览器必须:停止解析,下载脚本,然后运行。 只有在那之后它才能继续解析,因为 JavaScript 程序可以改变网页的内容(尤其是 HTML)。 这就是为什么JS 被称为解析器阻塞。
完成所有解析后,浏览器将构建文档对象模型 (DOM) 和级联样式表对象模型 (CSSOM)。 将它们组合在一起得到渲染树。 页面的非显示部分不会进入渲染树,因为它只包含绘制页面所需的数据。
倒数第二步是将渲染树转换为布局。 这个阶段也称为回流。 这就是计算每个渲染树节点的每个位置及其大小的地方。
最后,最后一步是画图。 它涉及根据浏览器在前一阶段计算的数据对像素进行着色。
优化相关结论
您可以猜到,网站性能优化的过程涉及对网站的更改,这些更改会减少:
- 必须传输的数据量
- 浏览器必须下载的资源数量(尤其是阻塞的资源)
- CRP的长度
此外,我们将深入研究它是如何完成的,但首先,有一条重要的规则需要遵守。
如何衡量绩效
优化的一个重要规则是:先测量,按需优化。 大多数浏览器的开发人员工具都有一个名为Performance的选项卡,这就是测量发生的地方。 在优化最快的初始(第一次)渲染时,最重要的是要查看以下事件的时间:
- 第一次油漆
- 第一次内容丰富的油漆
- 第一次有意义的油漆
在这里,“绘制”意味着页面的成功渲染,是关键渲染路径的最后阶段。 一些渲染可能会一个接一个地发生,因为浏览器会尝试尽快显示某些内容并稍后更新。
除了渲染时间之外,还有其他一些事情需要考虑——最重要的是,使用了多少阻塞资源以及下载它们需要多长时间。 进行测量后,可以在“性能”选项卡中找到此信息。
性能优化策略
鉴于我们在上面了解到的内容,网站性能优化有三种主要策略:
- 尽量减少通过网络传输的数据量,
- 减少通过网络传输的资源总数,以及
- 缩短关键渲染路径
1. 尽量减少要传输的数据量
首先,移除所有未使用的部分,例如 JavaScript 中无法访问的函数、带有从不匹配任何元素的选择器的样式以及被 CSS 永远隐藏的 HTML 标签。 其次,删除所有重复项。
然后,我建议建立一个自动缩小过程。 例如,它应该从您的后端服务中删除所有注释(但不是源代码)以及每个不包含附加信息的字符(例如 JS 中的空白字符)。
完成后,我们剩下的可以是文本。 这意味着我们可以安全地应用诸如 GZIP(大多数浏览器都理解)之类的压缩算法。
最后,还有缓存。 这在浏览器第一次呈现页面时无济于事,但在后续访问时会节省很多。 但是,记住两点至关重要:
- 如果您使用 CDN,请确保支持缓存并在此处正确设置。
- 而不是等待资源的到期日期到来,您可能希望有一种方法可以从您身边更早地更新它。 将文件的“指纹”嵌入到它们的 URL 中,以使本地缓存无效。
当然,应该为每个资源定义缓存策略。 有些可能很少改变或根本不会改变。 其他人的变化更快。 有些包含敏感信息,有些可能被认为是公开的。 使用“private”指令防止 CDN 缓存私有数据。

也可以优化网络图像,尽管图像请求不会阻止解析或呈现。
2. 减少关键资源的总数
“关键”仅指网页正确呈现所需的资源。 因此,我们可以直接跳过所有流程中没有涉及的样式。 还有所有的脚本。
样式表
为了告诉浏览器不需要特定的 CSS 文件,我们应该为所有引用样式表的链接设置media
属性。 使用这种方法,浏览器将只根据需要处理与当前media
(设备类型、屏幕尺寸)匹配的资源,同时降低所有其他样式表的优先级(它们无论如何都会被处理,但不会作为关键渲染的一部分)小路)。 例如,如果您将media="print"
属性添加到引用样式以打印页面的style
标记,则这些样式不会在不print
媒体时干扰您的关键渲染路径(即,当显示浏览器中的页面)。
为了进一步改进该过程,您还可以内联一些样式。 这为我们节省了至少一次往返服务器的时间,否则我们需要获取样式表。
脚本
如上所述,脚本是解析器阻塞的,因为它们可以改变 DOM 和 CSSOM。 因此,不改变它们的脚本不应该是块解析,从而节省我们的时间。
为了实现这一点,所有脚本标签都必须标有属性—— async
或defer
。
标有async
的脚本不会阻塞 DOM 构建或 CSSOM,因为它们可以在 CSSOM 构建之前执行。 但请记住,内联脚本无论如何都会阻止 CSSOM,除非您将它们放在 CSS 之上。
相比之下,标有defer
的脚本将在页面加载结束时进行评估。 因此,它们不应该影响文档(否则,它将触发重新渲染)。
换句话说,使用defer
,脚本在页面加载事件触发后才会执行,而async
让脚本在解析文档时在后台运行。
3.缩短关键渲染路径长度
最后,应将 CRP 长度缩短到可能的最小值。 部分地,上述方法将做到这一点。
作为样式标签属性的媒体查询将减少必须下载的资源总数。 script 标签属性defer
和async
将防止相应的脚本阻塞解析。
使用 GZIP 压缩、压缩和归档资源将减少传输数据的大小(从而也减少数据传输时间)。
内联一些样式和脚本可以减少浏览器和服务器之间的往返次数。
我们尚未讨论的是在文件中重新排列代码的选项。 按照最新的最佳性能理念,一个网站应该做的最快的第一件事就是展示 ATF 内容。 ATF 代表首屏。 这是立即可见的区域,无需滚动。 因此,最好以首先加载所需样式和脚本的方式重新排列与渲染相关的所有内容,而其他所有内容都停止 - 既不解析也不渲染。 并且永远记得在你做出改变之前和之后进行测量。
结论:优化涵盖您的整个堆栈
总而言之,网站性能优化包含了站点响应的各个方面,例如缓存、设置 CDN、重构、资源优化等,但是所有这些都可以逐步完成。 作为 Web 开发人员,您应该将本文作为参考,并始终记住在实验之前和之后测量性能。
浏览器开发人员尽最大努力优化您访问的每个页面的网站性能,这就是浏览器通常实现所谓的“预加载器”的原因。 这部分程序会在您以 HTML 格式请求的资源之前进行扫描,以便一次发出多个请求并让它们并行运行。 这就是为什么在 HTML(逐行)以及脚本标签中保持样式标签彼此靠近的原因。
此外,尝试批量更新 HTML 以避免多个布局事件,这些事件不仅由 DOM 或 CSSOM 的更改触发,而且由设备方向更改和窗口调整大小触发。
有用的资源和进一步阅读:
- PageSpeed 见解
- 缓存清单
- 一种测试是否为您的网站启用 GZIP 的方法
- 高性能浏览器网络:Ilya Grigorik 的一本书