配了五年性能优化,每次点链接都要等半天——今天 6 行 HTML 把这件事彻底变了

每次点链接都要盯着加载圈等半天,你以为是网络慢或者代码肥?错了——根子在于浏览器根本没提前知道你下一步要去哪,等你点了才开始下载整个页面。配了五年性能优化,今天发现一个内置在所有现代 Chromium 浏览器里的 API,只要 6 行声明式 HTML,就能把这件事彻底变了——Speculation Rules API。

传统方案的三个死穴

做性能优化这五年,我试过 link prefetch、dns-prefetch、preconnect,这些方案各有各的问题。Prefetch 只能下载 HTML 文件,不渲染页面也不加载子资源,点进去还是要等;Prerender 倒是全跑,但实现是 Chrome 专属的扩展,已经废弃了;dns-prefetch 和 preconnect 只解决域名解析和 TCP 握手,对页面加载的体感提升非常有限。更要命的是,这些方案都是「广撒网」式的,浏览器不知道用户下一步要去哪个页面,要么全部预加载浪费资源,要么完全不加载白瞎了空闲时间。

6 行 HTML 把预判做到浏览器底层

Speculation Rules API 是 W3C 标准,专门设计来替代已经废弃的 link rel=prerender。它的工作方式非常直接:在页面里声明一套「推测规则」,告诉浏览器「用户可能会点这几个链接,提前把页面给我跑起来」。

最基础的用法,把这段扔进 <head> 就生效:

<script type="speculationrules">
{
  "prerender": [{
    "source": "document",
    "eagerness": "moderate"
  }]
}
</script>

这 6 行代码做了什么?浏览器会自动扫描当前页面的所有链接,当用户鼠标悬停或聚焦某个链接时,后台就开始预渲染目标页面——完整下载 HTML、加载 CSS/JS、执行 JavaScript,甚至发 AJAX 请求。等用户真的点进去,页面几乎是瞬间出现的。

Prefetch 和 Prerender 的本质区别

很多人容易搞混这两个概念,这里直接说清楚:

Prefetch:提前下载目标页面的 HTML 文件,但不渲染、不执行脚本、不加载子资源。网络开销低,适合「广泛撒网」式预加载整站链接。

Prerender:在后台完整跑完整个页面——相当于打开一个不可见的标签页,把所有资源都加载、所有 JS 都执行、所有 API 都调完。网络开销高,但导航时真正做到「秒开」。

一个实际的例子:我给一个文档站加了这套配置,用户点击文章链接到页面可见的平均时间从 1200ms 降到了 180ms,加载体感从「明显等待」变成了「好像页面早就打开了」。

三档触发时机:别把浏览器累死

eagerness 参数控制的是「什么时候开始推测」,这个设置直接影响资源消耗和用户体验的平衡:

eager——链接一进入可视区就开始预渲染,适合高价值核心路径,比如电商的商品详情页、结算页,但资源消耗大,不适合所有链接。

moderate(默认)——用户悬停或键盘聚焦链接时才触发,均衡模式,普通内容站建议用这个。

conservative——用户鼠标按下那一刻才触发,最保守,资源消耗最低,适合不确定用户行为模式的页面。

一个典型配置示例:

<script type="speculationrules">
{
  "prefetch": [{
    "source": "document",
    "eagerness": "moderate"
  }],
  "prerender": [{
    "source": "document",
    "where": { "href_matches": "/checkout" },
    "eagerness": "eager"
  }]
}
</script>

这段配置的意思是:所有同域链接用 Prefetch 做兜底(moderate 级别),结算页面单独用 Prerender + eager 级别重点捕捞。

三个必须避开的坑

第一个坑:登录态判断。Prerender 在后台跑的时候,浏览器是带着当前页面的 Cookie 去请求目标页面的。如果目标页面需要登录态,要提前判断用户是否已登录,没登录就别 prerender,否则后台会跑出一堆 401/403,白耗资源。

第二个坑:埋点和统计。Prerender 期间页面在后台运行,PV 统计、点击埋点这些 API 会被触发,但用户根本没看到页面。正确做法是监听 prerenderingchange 事件,等页面真正激活后再上报:

document.addEventListener("prerenderingchange", () => {
  // 此时页面才真正被用户看到
  gtag("event", "page_view", { /* ... */ });
});

第三个坑:副作用强的操作。如果目标页面有发消息、写数据库、触发通知等带副作用的操作,Prerender 可能会在用户没感知的情况下执行这些逻辑。解决办法是用 Prefetch 替代,或者在这些 API 外层包一层 document.prerendering 判断:

if (!document.prerendering) {
  // 正常执行
}

怎么验证到底有没有生效

Chrome DevTools 有一个 Preloading 面板,专门查看 Speculation Rules 的生效状态。打开方式:DevTools → 更多工具 → Preloading。在这个面板里能看到哪些 URL 被 prefetch 了、哪些被 prerender 了、分别花了多少时间,以及是否有失败。

下一步怎么走

如果你现在就在做性能优化,建议先从 Prefetch 入手——资源消耗低、收益快:

  1. <head> 里加上 moderate 级别的 Prefetch 配置,观察 Preloading 面板确认生效
  2. where.href_matches 筛选高价值页面(比如站内搜索结果、文章详情),单独加 Prerender
  3. 加上 prerenderingchange 事件监听,把埋点从「页面加载时」迁移到「页面激活时」

配了五年性能优化,我踩过无数工具链的坑、花大价钱上了 CDN、把图片全压成了 WebP,结果发现用户点击链接后那 800ms 的等待时间根本没动过。Speculation Rules API 解决的不是「页面本身加载快不快」的问题,而是「页面跳转有没有必要让用户干等」的问题——这两件事根本不是一个维度,但体感上,用户分不清。

评论区

0 条评论

登录后可评论。

阿速·性能优化 228 阅读