推测性加载
推测性加载是指在实际访问相关页面之前执行导航操作(例如 DNS 获取、获取资源或渲染文档)的做法,其依据是对用户最可能接下来访问哪些页面的预测。
这些预测可以由开发者提供(例如,网站上最受欢迎的目的地列表),也可以由浏览器启发式地确定(例如,基于用户历史记录中热门网站)。如果使用成功,此类技术可以显著提高性能,使页面更快或在某些情况下即时可用。
本页面回顾了可用的推测性加载技术,以及何时以及如何使用它们来提高性能。
推测性加载机制
推测性加载有几种机制
- 预取(Prefetching)涉及在需要文档(或文档的一部分)之前,预先获取呈现文档所需的部分或全部资源,以便在需要呈现时,可以更快地完成呈现。
- 预渲染(Prerendering)更进一步,实际渲染内容,使其在需要时即可显示。根据实现方式的不同,这可能导致从旧页面到新页面的即时导航。
- 预连接(Preconnecting)通过预先执行部分或全部连接握手(即 DNS + TCP + TLS),来加快从给定源的未来加载速度。
注意:以上描述是高层次和概括性的。浏览器为实现预取和预渲染所做的具体操作取决于所使用的功能。更精确的功能描述在下面的推测性加载功能部分提供。
如何实现推测性加载?
推测性加载主要通过两种方式实现。
首先,一些浏览器会根据各种启发式方法自动预渲染页面,以提供自动的性能改进。具体如何实现取决于浏览器的实现。例如,Chrome 浏览器在地址栏中输入匹配字符串时会自动预渲染页面——如果它高度确信您会访问该页面(更多详细信息请参阅查看 Chrome 的地址栏预测)。此外,当在地址栏中输入搜索词时,如果搜索引擎指示,它也可能自动预渲染搜索结果页面。它使用与推测规则 API 相同的机制来完成此操作。
其次,有几种不同的平台功能可供开发人员使用,以提供关于他们希望浏览器执行何种推测性加载的指令。这些将在下一节中进行回顾。
推测性加载特性
<link rel="preconnect">
<link rel="preconnect">
向浏览器提供了一个提示,即用户可能需要来自指定资源源的资源,因此浏览器可以通过预先启动与该源的连接来提高性能。支持的浏览器将预先执行部分或全部连接握手(即 DNS + TCP + TLS)。
例如
<link rel="preconnect" href="https://example.com" />
<link rel="preconnect">
在浏览器中广泛支持,并将为任何未来的跨域 HTTP 请求、导航或子资源带来好处。它对同源请求没有好处,因为连接已经打开。
如果一个页面需要连接到许多第三方域,预连接所有这些域可能会适得其反。<link rel="preconnect">
提示最好只用于最关键的连接。对于其他连接,只需使用 <link rel="dns-prefetch">
来节省第一步的时间——DNS 查找。
您也可以将预连接作为 HTTP Link
标头来实现,例如
Link: <https://example.com>; rel="preconnect"
<link rel="dns-prefetch">
<link rel="dns-prefetch">
向浏览器提供了一个提示,即用户可能需要来自指定资源源的资源,因此浏览器可能可以通过预先执行该源的 DNS 解析来提高性能。它与 <link rel="preconnect">
相同,只是它只处理 DNS 部分。
同样,浏览器支持广泛,并且它对同源请求没有好处,因为连接已经打开。
例如
<link rel="dns-prefetch" href="https://example.com" />
注意:有关更多详细信息,请参阅使用 dns-prefetch。
<link rel="preload">
<link rel="preload">
向浏览器提供提示,说明当前页面上哪些资源具有高优先级,以便在页面<head>
中看到<link>
元素时可以尽早开始下载它们。
例如
<link rel="preload" href="main.js" as="script" />
<!-- CORS-enabled preload -->
<link
rel="preload"
href="https://www.example.com/fonts/cicle_fina-webfont.woff2"
as="font"
type="font/woff2"
crossorigin />
结果存储在每个文档的内存缓存中。如果您预加载了当前页面不作为子资源使用的内容,通常是浪费资源,尽管如果标头允许,结果可能会填充 HTTP 缓存。
您也可以将预加载作为 HTTP Link
标头来实现,例如
Link: <https://www.example.com/fonts/cicle_fina-webfont.woff2>; rel="preload"
现代浏览器对 <link rel="preload">
/<link rel="modulepreload">
的支持广泛。
<link rel="modulepreload">
<link rel="modulepreload">
向浏览器提供提示,说明当前页面上哪些 JavaScript 模块具有高优先级,以便它可以尽早开始下载它们。
例如
<link rel="modulepreload" href="main.js" />
它是 <link rel="preload">
的一个专用版本,用于JavaScript 模块,工作方式基本相同。但是,有一些区别:
- 浏览器知道资源是一个 JavaScript 模块,因为不需要
as
属性,并且它可以使用正确的凭据模式来避免重复获取。 - 浏览器不仅下载它并将其存储在缓存中,还会下载它,然后解析并直接编译到内存模块映射中。
- 浏览器还可以自动为模块依赖项执行相同的操作。
<link rel="prefetch">
<link rel="prefetch">
向浏览器提供了一个提示,即用户可能在未来的导航中需要目标资源,因此浏览器可以通过预先获取和缓存该资源来改善用户体验。<link rel="prefetch">
用于同站导航资源,或用于同站页面使用的子资源。
例如
<link rel="prefetch" href="main.js" />
预取可用于为可能的下一次导航获取 HTML 和子资源。一个常见的用例是拥有一个简单的网站着陆页,该页面获取网站其余部分使用的更“重型”资源。
<link rel="prefetch" href="/app/style.css" />
<link rel="prefetch" href="/landing-page" />
结果保留在磁盘上的 HTTP 缓存中。因此,它对于预取子资源很有用,即使它们不被当前页面使用。您也可以使用它来预取用户可能访问的下一个网站文档。但是,因此您需要小心标头——例如,某些Cache-Control标头可能会阻止预取(例如no-cache
或no-store
)。
许多浏览器现在都实现了某种形式的缓存分区,这使得 <link rel="prefetch">
对旨在供不同顶级网站使用的资源无用。这包括跨站点导航时的主文档。因此,例如,以下预取
<link rel="prefetch" href="https://news.example/article" />
将无法从 https://aggregator.example/
访问。
注意: <link rel="prefetch">
在功能上等同于带有 priority: "low"
选项的 fetch()
调用,只不过前者通常具有更低的优先级,并且它会在请求中设置 Sec-Purpose: prefetch
标头。
注意: prefetch
操作的 fetch 请求会生成一个包含 HTTP 标头 Sec-Purpose: prefetch
的 HTTP 请求。服务器可以使用此标头更改资源的缓存超时,或执行其他特殊处理。请求还将包含 Sec-Fetch-Dest
标头,其值设置为 empty
。请求中的 Accept
标头将与用于正常导航请求的值匹配。这允许浏览器在导航后找到匹配的缓存资源。如果返回响应,它将与请求一起缓存到 HTTP 缓存中。
<link rel="prerender">
已废弃 非标准
注意:此技术仅在 Chrome 中可用,现已废弃,并且不再执行其名称所暗示的预渲染。您应该改用推测规则 API,它取代了此功能。
<link rel="prerender">
向浏览器提供了一个提示,即用户可能在下一次导航中需要目标资源,因此浏览器可能可以通过预渲染该资源来提高性能。prerender
用于未来的导航,仅限同站,因此对于多页面应用程序 (MPA) 有意义,而不是单页面应用程序 (SPA)。
例如
<link rel="prerender" href="/next-page" />
它将获取引用的文档,然后获取任何静态可查找的链接资源并也获取它们,将结果存储在磁盘上的 HTTP 缓存中,超时时间为五分钟。例外情况是通过 JavaScript 加载的子资源——它不会找到这些。它还有其他问题——像 <link rel="prefetch">
一样,它也可能被 Cache-Control 标头阻止,并且由于浏览器缓存分区而对旨在供不同顶级站点使用的资源无用。
推测规则 API
推测规则 API 用于指定一组规则,这些规则决定浏览器应预取或预渲染哪些未来的文档。这些规则以 JSON 结构的形式提供,位于内联 <script type="speculationrules">
元素中,以及由 Speculation-Rules
响应头引用的外部文本文件中。
何时使用每个特性?
下表总结了上面详细介绍的功能,并提供了何时使用每个功能的指南。
推测性加载特性 | 用途 | 使用时机 |
---|---|---|
<link rel="preconnect"> |
跨域连接预热 | 在最关键的跨域连接上使用,以便在连接时提供性能改进。 |
<link rel="dns-prefetch"> |
跨域连接预热 | 在所有跨域连接上使用,以便在连接时提供小的性能改进。 |
<link rel="preload"> |
当前页面子资源的高优先级加载 | 用于在当前页面上更快地加载高优先级资源,以实现战略性性能改进。不要预加载所有内容,否则您将看不到好处。还有一些其他有趣的用途——请参阅 Smashing Magazine 上的预加载:它有什么用?(2016 年) |
<link rel="modulepreload"> |
当前页面 JavaScript 模块的高优先级加载 | 用于预加载高优先级 JavaScript 模块,以实现战略性性能改进。 |
<link rel="prefetch"> |
预填充 HTTP 缓存 | 用于预取同站未来导航资源或这些页面上使用的子资源。使用 HTTP 缓存,因此在文档预取方面存在许多问题,例如可能被 Cache-Control 标头阻止。在支持的情况下,请改用 推测规则 API 进行文档预取。 |
<link rel="prerender"> |
为下一次导航做准备 | 已废弃;建议您不要使用此功能。在支持的情况下,请改用推测规则 API 预渲染。 |
推测规则 API 预取 | 为下一次导航做准备 | 用于预取相同或跨站的未来导航文档。建议在支持时广泛采用;检查以确保页面可以安全预取。它不处理子资源预取;为此您需要使用 <link rel="prefetch"> 。 |
推测规则 API 预渲染 | 为下一次导航做准备 | 用于预加载同源的未来导航资源,以实现近乎即时的导航。在支持的情况下,用于高优先级页面;检查以确保页面可以安全预渲染。 |
另见
- 在 Chrome 中预渲染页面以实现即时页面导航 (developer.chrome.com, 2023)