学完这篇你能分清 preload、prefetch、preconnect 各自该用在什么场景,并拿到一段可直接贴进 <head> 的配置代码。
这三个 <link> 标签经常被混着用,其实它们解决的是完全不同的问题:preconnect 解决"连接慢",preload 解决"当前页面关键资源发现太晚",prefetch 解决"下一个页面资源能不能提前拿"。分清楚这三点,配起来就不会乱。
第一步:preconnect —— 提前和第三方域名握手
浏览器访问一个新域名,要依次做 DNS 解析、TCP 握手、TLS 协商(HTTPS),跨域资源这三步加起来常常几百毫秒。preconnect 就是提前把这些活干了。
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="dns-prefetch" href="https://fonts.gstatic.com">
典型场景:字体 CDN、第三方 API 域名、图片 CDN、你自己分离出来的静态资源域名。
注意:preconnect 别贪多,一般控制在 4 个以内。每个连接都会占用浏览器和服务器资源,写十几个反而互相抢带宽。跨域的 preconnect 要加 crossorigin,否则字体这类 CORS 请求会重新建一次连接,白做。
dns-prefetch 是只做 DNS 解析的轻量版,支持面更广,通常和 preconnect 成对写,作为老浏览器兜底。
第二步:preload —— 当前页面马上要用的资源,提前抢
浏览器解析 HTML 是从上往下走的。如果关键 CSS、字体、首屏大图藏在很深的位置(比如由 JS 动态插入、写在 CSS 里、写在 body 后面),浏览器发现它时已经晚了。preload 就是强行提前告诉浏览器:"这个资源现在就要,优先级调高。"
<!-- 关键字体 -->
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
<!-- 首屏大图 -->
<link rel="preload" href="/img/hero.webp" as="image" fetchpriority="high">
<!-- 关键 CSS(异步加载写法) -->
<link rel="preload" href="/css/critical.css" as="style" onload="this.rel='stylesheet'">
as 是必须写的,它决定请求头里的 Accept、优先级和是否走缓存复用;as 写错等于换个身份重新下载一遍,反而更慢。
注意:字体请求必须带 crossorigin,哪怕同域也一样,因为字体按 CORS 匿名模式请求,不写就会下载两次。另外 preload 的资源如果 3 秒内没被用上,Chrome 控制台会报 "resource was preloaded but not used" 警告——那就是白下载了,删掉对应标签。
第三步:prefetch —— 下一个页面可能用到的,空闲时慢慢拿
prefetch 的优先级最低,浏览器空闲时才下载,结果放进 HTTP 缓存,等用户真的跳到那个页面就直接命中。
<!-- 预取下一步最可能的页面 -->
<link rel="prefetch" href="/article/next-post.html">
<!-- 预取后续页面要用的 JS chunk -->
<link rel="prefetch" href="/js/detail-page.js" as="script">
常见落地点:商品列表页预取第一个详情页、文章页预取下一篇、登录后预取控制台首页。判断依据最好是真实行为数据,而不是"猜"。
注意:Safari 至今对 prefetch 支持有限,别把它当作功能依赖,只当加速手段。另外别用 prefetch 预取大量资源,尤其是移动端——用户可能压根不点,流量白花。
第四步:别漏了 modulepreload 和 fetchpriority
rel="modulepreload":给 ES Module 用的,除了下载还会提前解析依赖图,比 rel="preload" as="script" 更适合现代打包产物。
fetchpriority="high":直接标在 <img> 上的属性,用来提升 LCP 图片优先级,比 preload 更省事,两者别同时用在同一张图上。
第五步:配完怎么验证
打开 Chrome DevTools → Network 面板,右键表头勾选 Priority 和 Type 两列:
- 看 preload 的资源是不是
Highest 优先级、且只出现一次请求;
- 看 Console 有没有 "preloaded but not used" 警告;
- 打开 Application → Frames → 顶层文档,能看到预取缓存;
- 跑一次 Lighthouse,它会直接告诉你哪些域名值得加 preconnect。
小结
- preconnect:跨域域名提前握手,控制在 4 个内,跨域记得
crossorigin。
- preload:当前页面关键资源提前抢,
as 必须写对,字体必带 crossorigin,不用就要删。
- prefetch:下一个页面的资源空闲时拿,别滥用,Safari 支持有限。
- modulepreload 给 ES Module,fetchpriority 给 LCP 图片,别和 preload 叠用。
- 所有配置都要在 Network 面板验证,凭感觉加标签只会拖慢页面。