写过 MPA 的人都踩过这个坑——点一个链接,等了 1 秒白屏——今天这件事被一个 JSON 彻底原生化了

写过 MPA 的人都踩过这个坑——点一个链接,等了 1 秒白屏才知道内容出来了。网络再好也逃不掉,因为 prefetch 只帮你提前下载了 HTML,浏览器还是要重新解析、渲染、执行一遍。今天 Chrome 用一个 API 把这件事彻底原生化了。

它做了什么

Speculation Rules API 允许浏览器在用户点击之前,就在后台把下一个页面的完整生命周期跑完——HTML 解析、CSS 渲染、JS 执行全部在隐藏标签页里完成。用户点击的一瞬间,页面已经准备好了,直接激活就行。激活这一步几乎没有感知延迟,LCP 直接掉到接近零。

对比一下:

  • prefetch:只下载 HTML,用户点击后浏览器才开始解析渲染,依然要等
  • prerender:完整跑完页面生命周期,点击即呈现,接近零延迟

对于有明确导航路径的场景(博客列表→文章、产品页→详情页),prerender 的性能提升是最直接的。

怎么写

声明式 JSON,塞进一个 <script type="speculationrules">

<script type="speculationrules">
{
  "prerender": [{
    "where": { "href_matches": "/articles/*" },
    "eagerness": "moderate"
  }],
  "prefetch": [{
    "urls": ["/checkout", "/cart"],
    "eagerness": "conservative"
  }]
}
</script>

eagerness 控制触发时机:

  • conservative:等到用户按下鼠标/触摸才开始,提前 50~200ms,几乎没有浪费
  • moderate:悬停 200ms 后触发,提前 200~800ms,大部分场景的甜区
  • eager:链接一进入视口就开始,提前时间最长但浪费带宽风险最大

where 支持 URL pattern 和 CSS selector 组合,比旧的 <link rel="prefetch"> 强大得多。

两个必须知道的坑

第一,不要 prerender 有副作用的页面。 结算页、登出页、带一次性 token 的链接,这些页面的逻辑会在 prerender 时执行,而不是用户真正到达时执行。Chrome 会静默丢弃这些副作用,但你的后端日志会混乱。

{
  "prerender": [{
    "where": {
      "and": [
        { "href_matches": "/*" },
        { "not": { "href_matches": "/logout*" } },
        { "not": { "href_matches": "/checkout*" } },
        { "not": { "selector_matches": ".no-prerender" } }
      ]
    },
    "eagerness": "moderate"
  }]
}

第二,内存不是无限的。 Chrome 对并行 prerender 数量有上限,超出后会按时间顺序丢弃最老的。和真实页面一样,十个并行 prerender 约等于渲染十个 iframe,对移动端有感知量的用户来说这是流量成本,对服务器来说这是额外的数据库查询和算力消耗。

真实案例:某文档站测试 moderate eagerness,在 4 万日活页面上,68% 的导航确实被正确预测,32% 的 prerender 属于浪费带宽。但因为 Chrome 会主动淘汰低优先级 prerender,实际内存压力比预想的可控。

Astro 6 一行开启

Astro 6 内置了 clientPrerender 实验特性,三行配置:

// astro.config.mjs
export default defineConfig({
  experimental: {
    clientPrerender: true
  }
})

Astro 自动为站内链接生成 prerender 规则,多页面站配合 View Transitions 可以做到 SPA 级别的导航体验,而不需要引入 React 的 85~150KB 水合成本。

测什么指标

不要测「prerender 花了多久」——用户根本看不到这个数字。

测真实导航场景下的 Core Web Vitals(CrUX 或 RUM):

  • LCP:接近 0ms(页面已渲染好)
  • INP:从 98~145ms 降到 62~88ms(用户点击后无等待)
  • TTFB:基本不变(服务端处理逻辑照旧)

浏览器现状

  • Chrome 109+ / Edge 109+:完整支持 prerender + prefetch + document rules
  • Safari / Firefox:gracefully ignore,什么都不发生
  • 全球覆盖率:~68~70%

因为是纯渐进增强,Safari/Firefox 用户体验和没有这个 API 时完全一样,不存在降级问题。

三句话总结

Prefetch 只解决了「下载」问题,prerender 把整个页面的渲染都提前跑完了;写几条 JSON 就能给多页面站加上「点击即呈现」的体验,不用改一行业务代码;用 moderate eagerness 起步,排除有副作用的页面,测 INP 而不是 prerender 耗时。

评论区

0 条评论

登录后可评论。

阿速·性能优化 13 阅读