性能
性能优化方向
HTML 性能考虑
每个网站都以 HTML 文档的请求开始,这个请求在你的网站加载速度中起着很大的作用。这个模块涵盖了重要的概念,如HTML 缓存,解析器阻塞,渲染阻塞,等等,所以你可以确保你的网站的 HTML 的第一个请求是正确的。
最小化重定向
- HTTP 重定向:当客户端请求一个资源时,服务器可能会返回一个重定向响应,告诉客户端资源已经被移动到新的位置。重定向有两种类型:永久重定向(301 Moved Permanently)和临时重定向(302 Found)。永久重定向表示资源已经被 永久地移动到新的位置,而临时重定向表示资源只是暂时地移动到新的位置。
- 重定向的影响:重定向会减慢页面加载速度,因为它需要浏览器在新的位置发起额外的 HTTP 请求来获取资源。
- 重定向的类型:有两种类型的重定向:同源重定向和跨源重定向。同源重定向是在你的源(origin)内部发生的,你可以完全控制这种重定向。跨源重定向是由其他源发起的,你通常无法控制这种重定向。
- 跨源重定向:跨源重定向通常被广告、URL 缩短服务和其他第三方服务使用。虽然你无法控制跨源重定向,但你仍然应该避免多次重定向,例如,一个广告链接到一个 HTTP 页面,然后该页面又重定向到其 HTTPS 等价物,或者一个跨源重定向到达你的源,但然后触发了一个同源重定向。
常见的同一原始重定向模式是将用户从尾声结尾的 URL 重定向到非拖动斜线等效或 vice-versa,例如,将用户从 example.com/page/重定向到 example.com/page。在页面之间创建内部链接时,需要避免链接到以重定向响应的页面,并直接链接到正确的位置。
措施:
- 避免不必要的重定向:首先,你应该检查你的网站是否有不必要的重定向。例如,如果你有一个页面 A,它重定向到页面 B,然后页面 B 又重定向到页面 C,那么你应该直接将页面 A 重定向到页面 C,避免中间的重定向。
- 使用 HTTP/2:HTTP/2 支持服务器推送,这意味着服务器可以在浏览器请求资源之前就将资源发送给浏览器。这可以减少由于重定向而产生的额外 HTTP 请求。
- 预加载资源:你可以使用
<link rel="preload">
标签来预加载重定向后的资源。这样,当浏览器遇到重定向时,它已经预加载了重定向后的资源,从而减少了加载时间。 - 使用 HSTS:如果你的网站支持 HTTPS,你可以使用 HTTP Strict Transport Security (HSTS) 来避免 HTTP 到 HTTPS 的重定向。HSTS 告诉浏览器只使用 HTTPS 来访问你的网站,从而避免了重定向。
- 优化广告和第三方服务:如果你的网站使用了广告或第三方服务,你应该确保它们不会产生不必要的重定向。你可以与这些服务的提供商联系,要求他们优化他们的重定向。
缓存 HTML 响应
缓存HTML响应很困难,因为响应可能包括指向其他关键资源(例如CSS,JavaScript,图像和其他资源类型)的链接。这些资源可能在其各自的文件名中包含独特的指纹,该指纹根据文件的内容更改。这意味着的缓存的 HTML 文档可能会在部署后变成陈旧,因为它将包含对过时的子资源的引用。
尽管如此,较短的缓存生命周期比不缓存更有好处,比如允许在CDN上缓存资源,减少来自源服务器和浏览器的请求数量,允许重新验证资源,而不是再次下载资源。此方法最适合在任何上下文中都不会更改的静态内容,并且可以将缓存资源的适当时间设置为认为合适的分钟数。5 分钟的静态 HTML 资源是一个安全的赌注,并确保定期更新不会被忽视。
如果页面的 HTML 内容以某种方式个性化(例如对身份验证的用户)进行个性化,那么很可能根本不想缓解(安全性和新鲜度)。如果用户的浏览器缓存 HTML 响应,则无法使缓存无效。因此,最好避免在这种情况下完全缓存 HTML。
缓存 HTML 的一种谨慎的方法是使用 ETag 或 Last-Modified 响应头。ETag 也被称为实体标记头,它是唯一表示所请求资源的标识符,通常使用资源内容的散列
每当资源发生变化时,必须生成一个新的 ETag 值。在后续请求中,浏览器通过 If-None-Match 请求头发送 ETag 值。如果服务器上的 ETag 与浏览器发送的 ETag 匹配,则服务器响应 304 Not Modified 响应,浏览器使用缓存中的资源。虽然这仍然会导致网络延迟,但 304 Not Modified 响应比整个 HTML 资源要小得多。
但是,重新验证资源的新鲜度所涉及的网络延迟仍然是它自己的缺点。与 web 开发的许多其他方面一样,权衡和妥协是不可避免的。以这种方式缓存 HTML 的额外努力是否值得,或者最好是保持安全,根本不需要缓存 HTML 内容,这取决于。
测量服务器响应时间
如果未缓存响应,则服务器的响应时间高度依赖于托管服务提供商和后端应用程序堆栈。提供动态生成响应(例如从数据库获取数据)的网页很可能比静态网页具有更高的 TTFB,静态网页可以立即提供,而无需在后端花费大量计算时间。显示加载微调器,然后在客户端获取所有数据,将工作从更可预测的服务器端环境转移到可能不可预测的客户端环境。最小化客户端工作量通常会导致改进以用户为中心的指标。
如果用户在现场遇到缓慢的 TTFB,可以通过使用 Server-Timing
响应标头来公开有关在 服务器上花费时间的信息:
Server-Timing: auth;dur=55.5, db;dur=220
Server-Timing
标头的值可以包含多个指标,以及每个指标的持续时间。然后,可以使用导航计时 API 从现场用户那里收集这些数据,并进行分析以查看用户是否遇到延迟。在前面的代码片段中,响应标头包括两个计时:
- 对用户进行身份验证的时间 (
auth
),耗时 55.5 毫秒。 - 数据库访问时间 (
db
),耗时 220 毫秒。
可以在优化 TTFB 指南中找到有关
Server-Timing
响应标头的更多信息。https://web.dev/articles/optimize-ttfb#understanding_high_ttfb_with_server_timing
可能还想查看的托管基础设施,并确认有足够的资源来处理的网站收到 的流量。共享主机提供商通常容易受到高 TTFB 的影响,而提供更快响应时间的专用解决方案可能成本更高。
可以在 ismyhostfastyet.com 比较热门托管服务提供商的 TTFB。这些数据由从 Chrome 用户体验报告 (CrUX) 数据集中收集的真实用户体验组成。
压缩
基于文本的响应(如 HTML、JavaScript、CSS 和 SVG 图像)应进行压缩,以减少其在网络上的传输大小,以便更快地下载。使用最广泛的压缩算法是 gzip 和 Brotli。Brotli 比 gzip 提高了大约 15% 到 20%。
压缩通常由大多数网络托管服务提供商自动设置,但如果能够自己配置或调整压缩设置,则需要考虑一些重要事项:
- 尽可能使用 Brotli。如前所述,Brotli 比 gzip 提供了相当明显的改进,并且所有主流浏览器都支持 Brotli。尽可能使用 Brotli,但如果的网站在旧版浏览器上被大量用户使用,请确保使用 gzip 作为后备,因为任何压缩都比完全没有压缩好。
- 文件大小很重要。非常小的资源(小于 1 KiB)不能很好地压缩,有时甚至根本不压缩。任何类型的数据压缩的有效性都取决于压缩算法可以处理的大量数据,以便找到更多可压缩的数据位。文件越大,压缩效果越好,但是,不要仅仅因为可以更有效地压缩资源而提供非常大的资源。大型资源(例如 JavaScript 和 CSS)在浏览器解压缩后需要花费更多时间来解析和评估它们,并且即使它们只是略有变化,也可能会更频繁地更改,因为任何更改都会导致不同的文件哈希
- 了解动态压缩与静态压缩。动态压缩和静态压缩是何时应压缩资源的不同方法。动态压缩在 请求资源时压缩资源,有时在每次请求资源时都会压缩资源。另一方面,静态压缩会提前压缩文件,不需要在请求时执行压缩。静态压缩消除了压缩本身所涉及的延迟,在动态压缩的情况下,延迟可能会增加服务器响应时间。静态资源(如 JavaScript、CSS 和 SVG 图像)应静态压缩,而 HTML 资源(尤其是为经过身份验证的用户动态生成的资源)应动态压缩。
- 自行进行压缩具有挑战性,通常最好让内容分发网络 (CDN)(将在下一节中讨论)为处理此问题。但是,了解这些概念可以帮助辨别托管服务提供商是否正确使用压缩。这些知识可以帮助找到改进压缩设置的机会,以便它们为的网站带来最大的好处。
内容分发网络
内容分发网络 (CDN) 是一种分布式服务器网络,用于缓存源服务器中的资源,然后从物理上更接近用户的边缘服务器为资源提供服务。与用户的物理距离减少了往返时间 (RTT),而 HTTP/2 或 HTTP/3、缓存和压缩等优化使 CDN 能够比从源服务器获取内容更快地提供内容。在某些情况下,使用 CDN 可以显着改善网站的 TTFB。
关键路径
本模块涵盖了浏览器如何渲染网页背后的一些理论,特别是完成页面初始渲染所需的内容
关键渲染路径是 web 性能中的一个概念,用于处理页面在浏览器中初 始呈现的速度。本模块将介绍关键渲染路径背后的理论,涵盖诸如
- 渲染阻塞
- 解析器阻塞
资源等概念,以及它们如何在页面在浏览器中显示的速度中发挥关键作用。
关键路径
关键呈现路径是指在网页开始在浏览器中呈现之前所涉及的步骤。要呈现页面,浏览器需要 HTML 文档本身以及呈现该文档所需的所有关键资源。
渐进式渲染
web 本质上是分布式的。与使用前安装的本机应用程序不同,浏览器不能依赖于具有呈现页面所需的所有资源的网站。因此,浏览器非常擅长逐步呈现页面。本机应用通常有一个安装阶段,然后是一个运行阶段。但是,对于网页和 Web 应用程序,这两个阶段之间的界限要少得多,并且浏览器在设计时专门考虑到了这一点。
一旦浏览器拥有渲染页面的资源,它通常会开始这样做
- 何时渲染?
- 什么时候为时过早?
如果浏览器在只有一些 HTML 时尽快渲染,但在它没有任何 CSS 或必要的 JavaScript 之前,那么页面将暂时看起来破碎,并在最终渲染中发生很大变化。这比最初在一段时间内呈现空白屏幕更糟糕,直到浏览器拥有提供更好用户体验的初始呈现所需的更多资源。
另一方面,如果浏览器等待所有资源可用,而不是进行任何顺序渲染,那么用户将等待很长时间;
如果页面在更早的时间点可用,则通常不必要
浏览器需要知道它应该等待的最小资源数,以避免呈现明显损坏的体验。另 一方面,在向用户显示某些内容之前,浏览器也不应等待超过必要的时间。浏览器在执行初始渲染之前执行的一系列步骤称为关键渲染路径。
了解关键渲染路径有助于提高 Web 性能,确保不会阻止初始页面呈现超过必要的范围。与此同时,通过从关键渲染路径中删除初始渲染的必要资源,也不要让渲染过早发生,这一点也很重要。
步骤
关键渲染路径的步骤如下:
- 从 HTML 构造文档对象模型 (DOM)
- 从 CSS 构造 CSS 对象模型 (CSSOM)
- 应用任何更改 DOM 或 CSSOM 的 JavaScript
- 从 DOM 和 CSSOM 构造渲染树
- 在页面上执行样式和布局操作,以查看哪些元素适合何处
- 绘制内存中元素的像素
- 如果像素中的任何一个重叠,则合成像素
- 将所有生成的像素物理绘制到屏幕上
用图表示
只有在完成所有这些步骤后,用户才会在屏幕上看到内容。
这些步骤更多详情,移步:https://developer.chrome.com/articles/renderingng-architecture
此渲染过程会发生多次;
初始呈现会调用此过程,但随着更多影响页面呈现的资源可用,浏览器将重新运行此过程(或者可能只是 其中的一部分)以更新用户看到的内容;
关键渲染路径侧重于先前为初始渲染概述的过程,并依赖于该过程所需的关键资源。
关键资源
那有哪些关键资源呢?
浏览器需要等待下载一些关键资源,然后才能完成初始渲染。这些资源包括:
- HTML 的一部分
<head>
元素中的 CSS(阻塞渲染)<head>
元素中的 JavaScript(阻塞渲染 )
一个关键点是浏览器以流方式处理 HTML。一旦浏览器获取页面 HTML 的任何部分,浏览器就会开始处理它;
然后,浏览器可以(并且经常这样做)决定在接收页面的其余部分之前很好地呈现它;
重要的是,对于初始渲染,浏览器通常不会等待:
- 所有 HTML
- 字体
- 图像
<head>
元素之外的非渲染阻塞 JavaScript(例如, 放置在 HTML 末尾的<script>
元素)<head>
元素外部的非渲染阻塞 CSS,或属性media
值不适用于当前视口的 CSS
字体和图像通常被浏览器视为在后续页面重新呈现期间要填充的内容,因此它们不需要保留初始呈现;
但是,这可能意味着在初始渲染中会留下空白区域,而文本则隐藏在等待字体上,或者直到图像可用;
更糟糕的是,当没有为某些类型的内容预留足够的空间时(尤其是当 HTML 中没有提供图像尺寸时),页面的布局可能会在稍后加载此内容时发生变化;
用户体验的这一方面通过累积布局偏移 (CLS) 指标来衡量;
<head>
元素是处理关键渲染路径的关键;
优化 <head>
元素的内容是 Web 性能的一个关键方面。但是,要了解关键呈现路径,只需要知道 <head>
元素包含有关页面及其资源的元数据,但用户看不到任何实际内容;
可见内容包含在 <head>
元素后面的 <body>
元素中。在浏览器可以呈现任何内容之前,它既需要要呈现的内容,也需要有关如何呈现它的元数据;
但是,并非 <head>
元素中引用的所有资源对于初始页面呈现都是绝对必需的,因此浏览器只会等待那些资源;
若要确定关键呈现路径中包含哪些资源,需要了解渲染阻塞和解析器阻塞。
渲染阻塞
某些资源被认为非常重要,以至于浏览器会暂停页面呈现,直到处理完它们。默认情况下,CSS 属于此类别;
当浏览器看到 CSS 时(无论是 <style>
元素中的内联 CSS,还是 <link rel=stylesheet href="...">
元素指定的外部引用资源),浏览器都会避免呈现更多内容,直到它完成该 CSS 的下载和处理;
注意:虽然 CSS 默认情况下是渲染阻塞的,但可以通过更改
<link>
元素的media
属性来指定与当前条件不匹配的值,将其转换为非渲染阻塞资源:<link rel=stylesheet href="..." media=print>
。这在过去曾被用于允许非关键 CSS 以非渲染阻塞方式加载;
仅仅因为资源阻止渲染并不一定意味着它会阻止浏览器执行任何其他操作。浏览器试图尽可能高效,所以当浏览器看到它需要下载一个 CSS 资源时,它会请求它并暂停渲染,但仍然会继续处理其余的 HTML,并寻找其他工作;
渲染阻塞资源(如 CSS),被发现时,会阻塞页面的所有渲染,这意味着某些 CSS 是否被渲染阻塞取决于浏览器是否发现了它;
某些浏览器(最初是 Firefox,现在还有 Chrome)仅阻止渲染阻塞资源下方的内容渲染,这意味着,对于关键的渲染阻塞路径,我们通常对 <head>
中的渲染阻塞资源感兴趣,因为它们有效地阻塞了整个页面的渲染;
最近的一项创新是 blocking=render
添加到 Chrome 105 中的属性。这允许开发人员在处理元素之前将 <link>
或 <script>
<style>
元素显式标记为渲染阻塞,但仍允许解析器在此期间继续处理文档。
解析器阻塞
解析器阻塞资源是那些阻止浏览器通过继续解析 HTML 来查找其他工作的资源;
默认情况下,JavaScript 是解析器阻塞的(除非明确标记为异步或延迟),因为 JavaScript 可以在执行时更改 DOM 或 CSSOM。因此,浏览器不可能继续处理其他资源,直到它知道所请求的 JavaScript 对页面的 HTML 的全部影响。因此,同步 JavaScript 会阻止解析器;
解析器阻塞资源实际上也是渲染阻塞,由于解析器在完全处理之前无法继续通过解析阻塞资源,因此它无法访问和渲 染其之后的内容;
浏览器可以在等待期间渲染到目前为止收到的任何 HTML,但在关键渲染路径方面,任何解析器阻塞资源 <head>
实际上意味着所有页面内容都被阻止渲染;
阻塞解析器可能会产生巨大的性能成本,而不仅仅是阻塞渲染,出于这个原因,浏览器将尝试通过使用称为预加载扫描程序的辅助 HTML 解析器来降低此成本,以便在主 HTML 解析器被阻止时下载即将到来的资源;
虽然不如实际解析 HTML 好,但它至少允许浏览器中的网络功能在被阻止的解析器之前工作,这意味着它将来不太可能再次被阻止。
识别阻塞资源
许多性能审计工具可识别渲染和解析器阻塞资源。WebPageTest 在资源的 URL 左侧用橙色圆圈标记呈现阻塞资源:
在开始渲染之前,需要下载并处理所有渲染阻塞资源,瀑布流中的深绿色实线表示;
Lighthouse 还突出显示了阻塞渲染资源,但方式更微妙,并且仅当资源实际延迟页面渲染时。这有助于避免误报,可以最大程度地减少渲染阻塞。通过 Lighthouse 运行与前面的 WebPageTest 图相同的页面 URL 只会将其中一个样式表标识为渲染阻塞资源;
优化关键渲染路径
优化关键渲染路径涉及:
- 减少接收 HTML 的时间(由上一个模块中详述的首字节时间 (TTFB) 指标表示)
- 减少渲染阻塞资源的影响
很长一段时间以来,关键渲染路径一直关注初始渲染。然而,已经出现了更多以用户为中心的 Web 性能指标,这让人质疑关键渲染路径的终点应该是第一次绘制,还是随后的更令人满意的绘制之一。
另一种观点是将时间集中在最大内容绘制 (LCP) 之前,甚至是第一个内容绘制 (FCP) - 作为内容渲染路径(或其他人可能称之为关键路径)的一部分。在这种情况下,可能需要包含不一定阻塞的资源(这是关键渲染路径的典型定义),但对于渲染内容绘制是必需的。
无论对“关键”的确切定义如何,了解是什么阻碍了任何初始渲染和关键内容都很重要;
第一种绘制测量为用户渲染任何内容的第一个可能机会。理想情况下,这应该是有意义的东西,而不是像背景颜色这样的东西,但即使它是非内容性的,向用户呈现一些东西仍然有价值,这是衡量传统定义的关键渲染路径的论据。同时,衡量主要内容何时呈现给用户也有价值;