预加载与预连接
浏览器提供了多种资源提示(Resource Hints)机制,让开发者可以提前告诉浏览器即将需要的资源。preload、prefetch、preconnect、dns-prefetch 和 prerender 各有不同的用途和最佳实践。本节将详细介绍每种资源提示的用法、适用场景和注意事项。
前置知识
阅读本节前,建议先了解:图片优化策略
资源提示概览
| 提示 | 作用 | 时机 | 优先级 |
|---|---|---|---|
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 值 | 资源类型 | 说明 |
|---|---|---|
style | CSS | 预加载样式表 |
script | JavaScript | 预加载脚本 |
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>注意事项
- preload 不要过度:每个 preload 都会占用带宽
- preconnect 有连接限制:浏览器每个域名最多 6 个连接
- 字体必须设置 crossorigin:否则预加载的字体会被重新下载
- prefetch 使用率低时移除:如果用户没有导航到目标页面,prefetch 浪费带宽
- prefetch 优先级低于 preload:prefetch 不会与当前页面资源竞争带宽
最佳实践
- 对关键第三方域名使用
preconnect - 对关键 CSS 和字体使用
preload - 对下一页使用
prefetch - 谨慎使用
prerender - 字体预加载必须设置
crossorigin - 使用 Chrome DevTools Network 检查资源提示是否生效
- 移动端减少 prefetch 使用以节省带宽
下一节
继续学习:减少 DOM 节点数