了解 rel=prefetch 资源提示及其使用方法。
发布时间:2019 年 9 月 12 日;上次更新时间:2025 年 2 月 8 日
研究表明,加载时间越短,转化率就越高,用户体验也越好。如果您深入了解用户在您的网站中浏览的方式以及他们接下来可能会访问哪些网页,则可以提前下载这些网页的资源,从而缩短日后导航的加载时间。
本指南介绍了如何使用 <link rel=prefetch>
实现此目的,以便您高效地实现预加载。
使用 rel=prefetch
提升网站性能
向网页添加 <link rel=prefetch>
会指示浏览器下载用户日后可能需要的某些资源(例如脚本或 CSS 文件):
<link rel="prefetch" href="/css/styles.css">
prefetch
提示会为当前不需要的资源消耗额外的字节,因此需要谨慎使用此技术;仅在您确信用户需要资源时才预加载资源。建议在用户网速较慢时不预加载。您可以使用 Network Information API 检测这一点。
使用场景
预提取有许多用例,可通过提前下载资源来加快网页速度。
预提取后续网页
在后续网页可预测的情况下预提取 HTML 文档,以便在用户点击链接时立即加载网页。
例如,在商品详情页面中,您可以预加载列表中最热门商品的页面。在某些情况下,下一步导航甚至更容易预测:在购物车页面上,用户访问结账页的可能性通常很高,因此非常适合预加载。
虽然预提取资源确实会使用额外的带宽,但可以改进大多数性能指标。由于文档请求会导致缓存命中,因此首字节时间 (TTFB) 通常会大幅缩短。由于 TTFB 会降低,后续基于时间的指标(包括 Largest Contentful Paint [LCP] 和 First Contentful Paint [FCP])通常也会降低。
预提取静态资源
当可以预测用户可能会访问的后续部分时,预提取静态资源(例如脚本或样式表)。如果这些素材资源在多个网页中共享,这种方法尤为有用。
例如,Netflix 会利用用户在未登录状态下浏览网页的时间预加载 React,以便在用户登录后使用。因此,未来的导航可交互时间缩短了 30%。
预加载静态资源对性能指标的影响取决于要预加载的资源:
- 预提取图片可以显著缩短 LCP 图片元素的 LCP 时间。
- 预提取样式表可以同时缩短 FCP 和 LCP,因为下载样式表所需的网络时间将被消除。由于样式表会阻止渲染,因此在预提取时,它们可能会缩短 LCP。如果后续网页的 LCP 元素是使用
background-image
属性请求的 CSS 背景图片,系统还会将该图片作为预提取样式表的依赖资源进行预提取。 - 与在导航期间需要由网络先提取脚本相比,预提取 JavaScript 可让系统更快地处理预提取的脚本。这可能会影响网页的 Interaction to Next Paint (INP)。如果使用 JavaScript 在客户端上呈现标记,则可以通过缩短资源加载延迟时间来改善 LCP,并且包含网页 LCP 元素的标记的客户端渲染可以更早发生。
- 预提取当前网页尚未使用的 Web 字体可以消除布局偏移。在使用
font-display: swap;
的情况下,系统会消除字体的换货期,从而加快文本渲染速度并消除布局偏移。如果未来的网页使用了预提取的字体,并且该网页的 LCP 元素是使用 Web 字体的文本块,则该元素的 LCP 也会更快。
预提取按需 JavaScript 分块
通过对 JavaScript 软件包进行代码拆分,您可以最初只加载应用的部分内容,并延迟加载其余内容。如果您使用此方法,则可以将预加载应用于不立即需要但可能很快就会被请求的路由或组件。
例如,如果您的网页包含一个按钮,该按钮会打开一个包含表情符号选择器的对话框,您可以将其划分为三个 JavaScript 分块:首页、对话框和选择器。您可以先加载主页面和对话框,然后按需加载选择器。借助 webpack 等工具,您可以指示浏览器预加载这些按需分块。
如何实现 rel=prefetch
实现 prefetch
的最简单方法是将 <link>
标记添加到文档的 <head>
:
<head>
...
<link rel="prefetch" href="//css/styles.css">
...
</head>
您还可以使用 Link
HTTP 标头启动预提取:
Link: </css/style.css>; rel=prefetch
在 HTTP 标头中指定预提取提示的好处在于,浏览器无需解析文档即可找到资源提示,这在某些情况下可以带来小幅改进。
使用 webpack 魔法注释预提取 JavaScript 模块
借助 webpack,您可以预加载您有充分理由确信用户很快就会访问或使用到的路由或函数的脚本。
以下代码段会延迟加载 lodash 库中的排序函数,以对表单提交的一组数字进行排序:
form.addEventListener("submit", e => {
e.preventDefault()
import('lodash.sortby')
.then(module => module.default)
.then(sortInput())
.catch(err => { alert(err) });
});
您可以预加载此资源,而不是等待“提交”事件发生以加载此函数,以提高在用户提交表单时该资源在缓存中可用几率。webpack 允许您在 import()
中使用魔法注释来实现此目的:
form.addEventListener("submit", e => {
e.preventDefault()
import(/* webpackPrefetch: true */ 'lodash.sortby')
.then(module => module.default)
.then(sortInput())
.catch(err => { alert(err) });
});
这会指示 webpack 将 <link rel="prefetch">
标记注入 HTML 文档:
<link rel="prefetch" href="1.bundle.js">
预加载点播数据块的性能优势有点细微,但一般来说,您可以预期对依赖于这些点播数据块的互动做出更快的响应,因为这些数据块将立即可用。根据互动性质,这可能会对网页的 INP 产生积极影响。
预提取通常也会纳入整体资源优先级考虑范围。预提取资源时,系统会以尽可能低的优先级进行预提取。因此,任何预提取的资源都不会与当前网页所需的资源争用带宽。
使用 quicklink 和 Guess.js 进行智能预提取
您还可以使用底层使用 prefetch
的库实现更智能的预提取:
- quicklink 使用 Intersection Observer API 检测链接何时进入视口,并在空闲时间预加载关联的资源。附加信息:快捷链接的大小小于 1 KB!
- Guess.js 使用分析报告构建预测模型,以便智能预加载用户可能需要的内容。
如果用户的网络速度较慢或已开启 Save-Data
,quicklink 和 Guess.js 都会使用 Network Information API 来避免预加载。
预提取的内部机制
资源提示不是强制性说明,由浏览器自行决定是否以及何时执行这些提示。
您可以在同一网页中多次使用预提取。浏览器会将所有提示加入队列,并在空闲时请求每个资源。在 Chrome 中,如果预加载尚未完成,而用户导航到预加载的目标资源,浏览器会在导航时提取正在进行的加载(其他浏览器供应商可能会以不同的方式实现此操作)。
预提取的优先级为“最低”,因此预提取的资源不会与当前网页所需的资源争用带宽。
如果资源可缓存,预提取的文件会存储在 HTTP 缓存中,否则将被舍弃而不会被使用。
总结
使用 prefetch
可以提前下载未来需要的资源,从而显著提升网站的 Web 性能。大多数新型浏览器都支持 prefetch
。此技术需要加载可能不会使用的额外字节,因此请谨慎使用;仅在必要时使用,最好仅在快速网络上使用。