Skip to content

预加载与预连接

浏览器提供了多种资源提示(Resource Hints)机制,让开发者可以提前告诉浏览器即将需要的资源。preloadprefetchpreconnectdns-prefetchprerender 各有不同的用途和最佳实践。本节将详细介绍每种资源提示的用法、适用场景和注意事项。

前置知识

阅读本节前,建议先了解:图片优化策略

资源提示概览

提示作用时机优先级
dns-prefetch预解析 DNS当前页面
preconnect预建立连接当前页面
preload预加载资源当前页面
prefetch预取资源下一页面
prerender预渲染页面下一页面

dns-prefetch

预解析 DNS,提前解析域名的 IP 地址:

html
<!-- 预解析第三方域名 DNS -->
<link rel="dns-prefetch" href="//cdn.example.com">
<link rel="dns-prefetch" href="//fonts.googleapis.com">
<link rel="dns-prefetch" href="//api.example.com">

使用场景

html
<head>
  <!-- 页面中引用了以下域名的资源 -->
  <!-- 提前解析 DNS,减少后续请求的延迟 -->
  <link rel="dns-prefetch" href="//cdn.example.com">
  <link rel="dns-prefetch" href="//analytics.example.com">
</head>
<body>
  <img src="https://cdn.example.com/images/photo.jpg" alt="照片" />
  <script async src="https://analytics.example.com/analytics.js"></script>
</body>

preconnect

预建立网络连接(DNS + TCP + TLS),比 dns-prefetch 更进一步:

html
<!-- 预连接到 CDN(DNS + TCP + TLS) -->
<link rel="preconnect" href="https://cdn.example.com" crossorigin>

<!-- 预连接到 API 服务器 -->
<link rel="preconnect" href="https://api.example.com">

preconnect 参数

html
<!-- 完整的预连接 -->
<link rel="preconnect" href="https://cdn.example.com" crossorigin>

<!-- crossorigin 告诉浏览器预连接包括 TLS 握手 -->
<!-- 对于需要跨域请求的资源(如字体),必须设置 crossorigin -->

使用场景

html
<head>
  <meta charset="UTF-8">
  <title>Preconnect 示例</title>

  <!-- 预连接到字体 CDN -->
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

  <!-- 预连接到图片 CDN -->
  <link rel="preconnect" href="https://cdn.example.com" crossorigin>

  <!-- 加载字体 -->
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC">
</head>

不要过度使用 preconnect

每个 preconnect 都会占用浏览器连接池资源。建议同一域名最多预连接 2-4 个。

preload

预加载当前页面需要的关键资源:

html
<!-- 预加载关键 CSS -->
<link rel="preload" href="/css/critical.css" as="style">

<!-- 预加载关键字体 -->
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>

<!-- 预加载关键图片 -->
<link rel="preload" href="/images/hero-banner.webp" as="image">

<!-- 预加载关键 JavaScript -->
<link rel="preload" href="/js/app.js" as="script">

as 属性值

as 值资源类型说明
styleCSS预加载样式表
scriptJavaScript预加载脚本
image图片预加载图片
font字体必须设置 crossorigin
fetch任意数据用于 XHR/Fetch 请求

预加载图片

html
<head>
  <!-- 预加载首屏图片 -->
  <link rel="preload" href="/images/hero-banner.webp" as="image" fetchpriority="high">
</head>
<body>
  <img src="/images/hero-banner.webp" alt="首屏横幅" fetchpriority="high" />
</body>

预加载字体

html
<head>
  <!-- 预连接字体服务器 -->
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

  <!-- 预加载字体文件 -->
  <link rel="preload" href="/fonts/noto-sans-sc-regular.woff2" as="font" type="font/woff2" crossorigin>
</head>

prefetch

预取下一页面可能需要的资源:

html
<!-- 预取下一页面的关键资源 -->
<link rel="prefetch" href="/next-page.html">
<link rel="prefetch" href="/images/next-page-hero.webp" as="image">
<link rel="prefetch" href="/js/next-page.js" as="script">

使用场景

html
<!-- 预取下一页 -->
<nav aria-label="分页">
  <a href="/articles?page=1" aria-current="page">1</a>
  <a href="/articles?page=2">2</a>
  <a href="/articles?page=3">3</a>
</nav>

<!-- 预取下一页内容 -->
<link rel="prefetch" href="/articles?page=2">

prerender

预渲染整个页面(在后台加载并渲染下一页):

html
<!-- 预渲染下一页面 -->
<link rel="prerender" href="/likely-next-page.html">

prerender 谨慎使用

prerender 会消耗大量网络带宽和 CPU/内存资源。仅在用户有很大概率访问下一页时使用。

Speculation Rules(新标准)

html
<!-- 新的 Speculation Rules API(Chrome 121+) -->
<script type="speculationrules">
{
  "prerender": [
    {
      "source": "list",
      "urls": ["/article/2", "/article/3"]
    }
  ],
  "prefetch": [
    {
      "source": "document",
      "where": {
        "and": [
          { "selector_matches": "a[href]" },
          { "not": { "selector_matches": "a[download]" } }
        ]
      }
    }
  ]
}
</script>

完整示例

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>资源预加载示例</title>

  <!-- DNS 预解析 -->
  <link rel="dns-prefetch" href="//analytics.example.com">

  <!-- 预连接到 CDN 和字体服务器 -->
  <link rel="preconnect" href="https://cdn.example.com" crossorigin>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

  <!-- 预加载关键资源 -->
  <link rel="preload" href="/css/critical.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
  <link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
  <link rel="preload" href="/images/hero.webp" as="image" fetchpriority="high">

  <!-- 预取下一页资源 -->
  <link rel="prefetch" href="/next-page/data.json" as="fetch">
</head>
<body>
  <!-- 首屏内容 -->
  <img src="/images/hero.webp" alt="首屏横幅" fetchpriority="high" width="1200" height="600" />

  <!-- 非关键资源 -->
  <script defer src="/js/app.js"></script>
</body>
</html>

注意事项

  1. preload 不要过度:每个 preload 都会占用带宽
  2. preconnect 有连接限制:浏览器每个域名最多 6 个连接
  3. 字体必须设置 crossorigin:否则预加载的字体会被重新下载
  4. prefetch 使用率低时移除:如果用户没有导航到目标页面,prefetch 浪费带宽
  5. prefetch 优先级低于 preload:prefetch 不会与当前页面资源竞争带宽

最佳实践

  • 对关键第三方域名使用 preconnect
  • 对关键 CSS 和字体使用 preload
  • 对下一页使用 prefetch
  • 谨慎使用 prerender
  • 字体预加载必须设置 crossorigin
  • 使用 Chrome DevTools Network 检查资源提示是否生效
  • 移动端减少 prefetch 使用以节省带宽

下一节

继续学习:减少 DOM 节点数

参考链接