Prefetch 与 Preload

深入理解浏览器资源预取机制:preload、prefetch、preconnect、prerender 的区别和使用场景。


四种预取机制

浏览器提供了多种预取机制,帮助提前加载资源:

机制 作用时机 优先级 使用场景
preload 当前页面 当前页面必需的资源
prefetch 未来页面 下一个页面需要的资源
preconnect 当前页面 提前建立连接
prerender 未来页面 提前渲染整个页面

Preload

提前加载当前页面需要的资源:

<!-- 提前加载关键 CSS -->
<link rel="preload" href="/styles.css" as="style">

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

<!-- 提前加载字体 -->
<link rel="preload" href="/fonts/myfont.woff2" as="font" crossorigin>

何时使用 Preload

  • 首屏渲染必需的资源
  • 当前页面需要但 HTML 解析时不会自动发现的资源
  • 字体(浏览器不会自动发现跨域字体)

as 属性

必须指定正确的 as 值:

  • style:CSS
  • script:JavaScript
  • font:字体文件
  • image:图片
  • fetch:API 请求

Prefetch

提前获取未来页面需要的资源:

<!-- 预测用户下一步会访问的页面资源 -->
<link rel="prefetch" href="/next-page.css">
<link rel="prefetch" href="/next-page.js">

与 Preload 的区别

  • preload:当前页面必需,高优先级
  • prefetch:未来页面需要,低优先级

使用场景

// 搜索场景:用户输入时预取搜索结果
searchInput.addEventListener('input', () => {
  const query = searchInput.value;
  if (query.length > 2) {
    // 预取搜索建议
    const link = document.createElement('link');
    link.rel = 'prefetch';
    link.href = `/api/suggest?q=${encodeURIComponent(query)}`;
    document.head.appendChild(link);
  }
});

Preconnect

提前建立网络连接:

<!-- 提前建立与 CDN 的连接 -->
<link rel="preconnect" href="https://cdn.example.com">

<!-- 包括 TLS 握手 -->
<link rel="preconnect" href="https://cdn.example.com" crossorigin>

使用场景

  • 第三方域名(字体、API、分析工具)
  • CDN 域名
  • 任何你知道会访问的域名

dns-prefetch vs preconnect

  • dns-prefetch:只解析 DNS
  • preconnect:DNS + TCP 握手 + TLS 握手
<!-- 基础版:只 DNS 解析 -->
<link rel="dns-prefetch" href="https://cdn.example.com">

<!-- 完整版:DNS + 连接 -->
<link rel="preconnect" href="https://cdn.example.com">

Prerender

提前渲染整个页面:

<!-- 预测用户下一步会访问的页面 -->
<link rel="prerender" href="/next-page.html">

页面会在后台完全渲染(包括执行 JavaScript),当用户导航到该页面时,内容已经准备好了。

使用注意

  • 会消耗大量资源和带宽
  • 如果预渲染的页面有音频/视频,会自动播放
  • 可能导致隐私问题(执行 JS)

实际应用场景

场景一:字体加载优化

<!-- 先 preconnect,再 preload 字体 -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preload" href="/fonts/myfont.woff2" as="font" crossorigin>

场景二:路由懒加载

// React 路由配置
const routes = [
  {
    path: '/dashboard',
    component: lazy(() => import('./Dashboard'))
  }
];

// 在 Dashboard 路由渲染前预取
<Link
  to="/dashboard"
  onMouseEnter={() => {
    const link = document.createElement('link');
    link.rel = 'prefetch';
    link.href = '/dashboard-chunk.js';
    document.head.appendChild(link);
  }}
>
  Go to Dashboard
</Link>

这一章想说的

四种预取机制各有用途:

  • preload:提前加载当前页面必需的资源
  • prefetch:提前获取未来页面需要的资源
  • preconnect:提前建立网络连接
  • prerender:提前渲染整个页面(谨慎使用)

合理使用预取可以显著提升用户体验,但不要滥用——预取会消耗带宽和资源。


延展阅读