通过资源提示协助浏览器

在最后一个关于优化资源加载的模块中,您了解了 CSS 和 JavaScript 等各种网页资源如何影响网页加载速度,以及如何优化这些资源及其传送方式来加快网页的呈现速度。 现在是时候深入了解资源加载的更高级方面了,这涉及使用资源提示来帮助浏览器更快地加载资源。

资源提示可告知浏览器如何加载资源以及如何确定资源优先级,从而帮助开发者进一步优化网页加载时间。最初引入的是一组初始资源提示,例如 preconnectdns-prefetch。不过,随着时间的推移,preload 和 Fetch Priority API 也相继推出,以提供更多功能。

资源提示会指示浏览器提前执行某些操作,从而提高加载性能。资源提示可以执行各种操作,例如提前执行 DNS 查找、提前连接到服务器,甚至在浏览器通常会发现资源之前就获取资源。

资源提示可以在 HTML 中指定(通常在 <head> 元素中尽早指定),也可以设置为 HTTP 标头。在此模块的范围内,我们将介绍 preconnectdns-prefetchpreload,以及 prefetch 提供的推测性提取行为。

preconnect

preconnect 提示用于建立与另一个来源的连接,您将从该来源提取关键资源。例如,您可能在 CDN 或其他跨源上托管图片或资源:

<link rel="preconnect" href="https://example.com">

通过使用 preconnect,您可以预料到浏览器计划在不久的将来连接到特定的跨源服务器,并且浏览器应尽快打开该连接,最好是在等待 HTML 解析器或预加载扫描器执行此操作之前。

如果网页上有大量跨源资源,请为对当前网页而言最重要的资源使用 preconnect

Chrome DevTools 的“网络”面板中资源的连接时间截图。连接设置包括停滞时间、代理协商、DNS 查找、连接设置和 TLS 协商。
Chrome 开发者工具的网络面板中显示的连接时间可视化图表。红框中的时间是与跨源服务器建立连接所涉及的时间,preconnect 可以通过更早地建立连接(而不是在发现跨源资源时建立连接)来缓解这种情况。

preconnect 的常见用例是 Google 字体。Google Fonts 建议您将 preconnect 连接到提供 @font-face 声明的 https://fonts.googleapis.com 网域,以及提供字体文件的 https://fonts.gstatic.com 网域。

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

crossorigin 属性用于指明是否必须使用跨源资源共享 (CORS) 来提取资源。使用 preconnect 提示时,如果从来源下载的资源(例如字体文件)使用 CORS,则需要向 preconnect 提示添加 crossorigin 属性。

dns-prefetch

虽然提前打开与跨源服务器的连接可以显著缩短初始网页加载时间,但同时与许多跨源服务器建立连接可能并不合理或不可能。如果您担心自己可能过度使用 preconnect,那么 dns-prefetch 提示是一种成本低得多的资源提示。

顾名思义,dns-prefetch 不会与跨源服务器建立连接,而只是提前为其执行 DNS 查找。当域名解析为其底层 IP 地址时,就会发生 DNS 查找。虽然设备和网络层级的多层 DNS 缓存有助于加快此过程,但仍需要一定的时间。

<link rel="dns-prefetch" href="https://fonts.googleapis.com">
<link rel="dns-prefetch" href="https://fonts.gstatic.com">

DNS 查找的费用相当低,因此在某些情况下,与 preconnect 相比,DNS 查找可能更适合。特别是,在链接会引导用户前往其他网站的情况下,dns-prefetch 可能是理想的资源提示,因为您认为用户很可能会点击这些链接。 dnstradamus 就是这样一种工具,它使用 JavaScript 自动执行此操作,并使用 Intersection Observer API 在用户滚动到指向其他网站的链接时,将 dns-prefetch 提示注入到当前网页的 HTML 中。

preload

preload 指令用于针对呈现网页所需的资源发起早期请求:

<link rel="preload" href="/lcp-image.jpg" as="image">

preload 指令应仅限于后期发现的关键资源。最常见的用例是字体文件、通过 @import 声明提取的 CSS 文件,或可能是 Largest Contentful Paint (LCP) 候选对象的 CSS background-image 资源。在这种情况下,预加载扫描器不会发现这些文件,因为资源是在外部资源中引用的。

preconnect 类似,如果您预加载 CORS 资源(例如字体),则 preload 指令需要 crossorigin 属性。如果您不添加 crossorigin 属性(或为非 CORS 请求添加该属性),浏览器会下载资源 两次,从而浪费本可更好地用于其他资源的带宽。

<link rel="preload" href="/font.woff2" as="font" crossorigin>

在上述 HTML 代码段中,浏览器被指示使用 CORS 请求预加载 /font.woff2,即使 /font.woff2 位于同一网域中也是如此。

prefetch

prefetch 指令用于针对可能用于未来导航的资源发起低优先级请求:

<link rel="prefetch" href="/next-page.css" as="style">

此指令在很大程度上遵循与 preload 指令相同的格式,只是 <link> 元素的 rel 属性使用值 "prefetch"。不过,与 preload 指令不同的是,prefetch 在很大程度上是推测性的,因为您是为可能发生也可能不发生的未来导航启动资源提取。

有时,使用 prefetch 可能是有益的,例如,如果您已确定网站上大多数用户都会遵循某个用户流程来完成操作,那么为这些未来网页的关键渲染资源使用 prefetch 有助于缩短这些网页的加载时间。

Fetch Priority API

您可以通过 Fetch Priority APIfetchpriority 属性来提高资源的优先级。您可以将该属性与 <link><img><script> 元素搭配使用。

<div class="gallery">
  <div class="poster">
    <img src="img/poster-1.jpg" fetchpriority="high">
  </div>
  <div class="thumbnails">
    <img src="img/thumbnail-2.jpg" fetchpriority="low">
    <img src="img/thumbnail-3.jpg" fetchpriority="low">
    <img src="img/thumbnail-4.jpg" fetchpriority="low">
  </div>
</div>

默认情况下,系统会以较低的优先级提取图片。布局完成后,如果发现图片位于初始视口内,则优先级会提升为 High 优先级。在上面的 HTML 代码段中,fetchpriority 会立即告知浏览器以 High 优先级下载较大的 LCP 图片,而不太重要的缩略图则以较低的优先级下载。

现代浏览器分两个阶段加载资源。第一阶段专用于关键资源,在所有阻塞脚本下载并执行完毕后结束。在此阶段,优先级资源可能会延迟下载。通过使用 fetchpriority="high",您可以提高资源的优先级,使浏览器能够在第一阶段下载该资源。

资源提示演示

知识测验

preconnect 资源提示有何作用?

仅对跨源服务器执行 DNS 查找。
打开与跨源服务器的连接,包括 DNS 查询,以及在浏览器发现该服务器之前进行的连接和 TLS 协商。

Fetch Priority API 可让您执行哪些操作?

指定 <link><img><script> 元素的相对优先级。
指定下载当前网页 HTML 的优先级。

何时应使用 prefetch 提示?

当您非常有把握用户需要预提取的资源或网页时。
用户可能需要的任何资源或网页,无论他们将来是否真的需要这些资源或网页。
如果用户未明确表示偏好减少数据使用量。

接下来:图片效果

到目前为止,您可能已经对网页 HTML、<head> 元素和资源提示的一般性能注意事项有了相当的了解。不过,还有一些额外的优化措施专门针对网页通常加载的不同资源类型。接下来,我们将在下一个模块中介绍图片性能,该模块可帮助您尽可能快地加载网站的图片,无论用户使用的是什么设备。