当您打开网页时,浏览器会从服务器请求 HTML 文档,解析其内容,并为任何引用的资源提交单独的请求。作为开发者,您已经了解您的页面需要的所有资源以及哪些资源最重要。您可以使用这些知识提前请求关键资源,并加快加载过程。这篇文章解释了如何使用 <link rel="preload">
来实现这一点。
预加载的工作原理
预加载最适合浏览器通常稍后才发现的资源。

@font-face
规则定义。浏览器仅在完成下载和解析样式表后才加载字体文件。通过预加载特定资源,您是在告诉浏览器您希望比浏览器原本发现它的时间更早地获取它,因为您确信它对于当前页面很重要。

关键请求链表示浏览器优先处理和获取的资源顺序。Lighthouse 将此链中第三级的资源标识为稍后发现的资源。您可以使用预加载关键请求审核来识别要预加载哪些资源。
您可以通过将带有 rel="preload"
的 <link>
标记添加到 HTML 文档的头部来预加载资源
<link rel="preload" as="script" href="critical.js">
浏览器会缓存预加载的资源,以便在需要时立即使用。(它不会执行脚本或应用样式表。)
资源提示(例如,preconnect
和 prefetch
)会根据浏览器的判断执行。preload
则不同,它对于浏览器是强制性的。现代浏览器在优先处理资源方面已经做得相当好了,这就是为什么有必要谨慎使用 preload
,并且仅预加载最关键的资源。
未使用的预加载会在 Chrome 中触发控制台警告,大约在 load
事件发生 3 秒后。
用例
预加载 CSS 中定义的资源
使用 @font-face
规则定义的字体或 CSS 文件中定义的背景图片,在浏览器下载和解析这些 CSS 文件之前是无法被发现的。预加载这些资源可确保它们在 CSS 文件下载之前被获取。
预加载 CSS 文件
如果您正在使用 关键 CSS 方法,您需要将 CSS 拆分为两个部分。渲染首屏内容所需的关键 CSS 内联在文档的 <head>
中,而非关键 CSS 通常使用 JavaScript 延迟加载。等待 JavaScript 执行后再加载非关键 CSS 可能会导致用户滚动时渲染延迟,因此使用 <link rel="preload">
更早地启动下载是个好主意。
预加载 JavaScript 文件
由于浏览器不执行预加载的文件,因此预加载对于将获取与 执行 分开很有用,这可以改善诸如可交互时间之类的指标。如果您拆分您的 JavaScript 包并且仅预加载关键代码块,则预加载效果最佳。
如何实现 rel=preload
实现 preload
最简单的方法是将 <link>
标记添加到文档的 <head>
中
<head>
<link rel="preload" as="script" href="critical.js">
</head>
提供 as
属性有助于浏览器根据预取资源的类型设置优先级,设置正确的标头,并确定缓存中是否已存在该资源。此属性的接受值包括:script
、style
、font
、image
和 其他值。
某些类型的资源(如字体)以 匿名模式 加载。对于这些资源,您必须使用 preload
设置 crossorigin
属性
<link rel="preload" href="ComicSans.woff2" as="font" type="font/woff2" crossorigin>
<link>
元素还接受 type
属性,其中包含链接资源的 MIME 类型。浏览器使用 type
属性的值来确保仅当支持资源的文件类型时才预加载资源。如果浏览器不支持指定的资源类型,它将忽略 <link rel="preload">
。
您还可以通过 Link
HTTP 标头预加载任何类型的资源
Link: </css/style.css>; rel="preload"; as="style"
在 HTTP 标头中指定 preload
的一个好处是,浏览器不需要解析文档来发现它,这在某些情况下可以提供小的改进。
使用 webpack 预加载 JavaScript 模块
如果您正在使用模块打包器来创建应用程序的构建文件,则需要检查它是否支持注入预加载标记。使用 webpack 4.6.0 或更高版本,通过在 magic comments 内使用 import()
来支持预加载
import(_/* webpackPreload: true */_ "CriticalChunk")
如果您使用的是旧版本的 webpack,请使用第三方插件,例如 preload-webpack-plugin。
预加载对 Core Web Vitals 的影响
预加载是一项强大的性能优化措施,可影响加载速度。此类优化可能会导致您网站的 Core Web Vitals 发生变化,了解这些变化非常重要。
最大内容绘制 (LCP)
当涉及到字体和图像时,预加载对 最大内容绘制 (LCP) 具有强大的影响,因为图像和文本节点都可以成为 LCP 候选对象。Hero 图像和使用 Web 字体渲染的大量文本可以从放置良好的预加载提示中显着受益,并且应该在有机会更快地向用户交付这些重要内容位时使用。
但是,在预加载和其他优化方面,您需要小心!尤其要避免预加载过多资源。如果优先处理的资源过多,实际上没有一个资源被优先处理。过多的预加载提示的影响对于那些带宽争用更加明显的较慢网络上的用户尤其不利。
相反,请专注于您知道将从放置良好的预加载中受益的少量高价值资源。预加载字体时,请确保您以 WOFF 2.0 格式提供字体,以尽可能减少资源加载时间。由于 WOFF 2.0 具有 出色的浏览器支持,如果 LCP 候选对象是文本节点,则使用 WOFF 1.0 或 TrueType (TTF) 等旧格式会延迟您的 LCP。
当涉及到 LCP 和 JavaScript 时,您需要确保从服务器发送完整的标记,以便 浏览器的预加载扫描器 正常工作。如果您提供的体验完全依赖于 JavaScript 来渲染标记,并且无法发送服务器渲染的 HTML,那么最好介入浏览器预加载扫描器无法介入的地方,并预加载那些只有在 JavaScript 完成加载和执行后才能被发现的资源。
累积布局偏移 (CLS)
累积布局偏移 (CLS) 是一个尤其重要的指标,尤其是在 Web 字体方面,并且 CLS 与使用 font-display
CSS 属性 来管理字体加载方式的 Web 字体具有显着的相互作用。为了最大限度地减少与 Web 字体相关的布局偏移,请考虑以下策略
- 在使用
font-display
的默认block
值时预加载字体。 这是一个微妙的平衡。阻止字体显示而不使用后备字体可能会被认为是用户体验问题。一方面,使用font-display: block;
加载字体消除了与 Web 字体相关的布局偏移。另一方面,您仍然希望尽快加载这些 Web 字体,如果它们对用户体验至关重要。将预加载与font-display: block;
结合使用可能是一种可以接受的折衷方案。 - 在使用
font-display
的fallback
值时预加载字体。fallback
是swap
和block
之间的折衷方案,因为它具有极短的阻止期。 - 在不进行预加载的情况下,对
font-display
使用optional
值。 如果 Web 字体对于用户体验不是至关重要的,但仍用于渲染大量页面文本,请考虑使用optional
值。在不利条件下,optional
将在加载后备字体的情况下显示页面文本,同时在后台加载字体以供下次导航使用。这些条件下的最终结果是改进的 CLS,因为系统字体将立即呈现,而后续页面加载将立即加载字体而不会发生布局偏移。
当涉及到 Web 字体时,CLS 是一个难以优化的指标。与往常一样,在实验室数据中进行实验,但相信您的现场数据来确定您的字体加载策略是改善 CLS 还是使其变得更糟。
交互到下次绘制 (INP)
交互到下次绘制 是一项衡量对用户输入响应速度的指标。由于 Web 上的大部分交互性都是由 JavaScript 驱动的,因此预加载驱动重要交互的 JavaScript 可能有助于保持页面的 INP 较低。但是,请注意,如果在启动期间预加载过多的 JavaScript,如果过多的资源争用带宽,则可能会带来意想不到的负面后果。
您还需要小心如何进行代码拆分。代码拆分是减少启动期间加载的 JavaScript 量的绝佳优化方法,但如果交互依赖于在交互开始时立即加载的 JavaScript,则可能会延迟交互。为了弥补这一点,您需要检查用户的意图,并在交互发生之前为所需的 JavaScript 代码块注入预加载。一个示例可能是预加载验证表单内容所需的 JavaScript,当表单中的任何字段获得焦点时。
结论
为了提高页面速度,请预加载浏览器稍后才发现的重要资源。预加载所有内容会适得其反,因此请谨慎使用 preload
,并衡量其在真实世界中的影响。