HTML 预加载技术详解:preload / prefetch / preconnect 怎么用

最长的电影
最长的电影 正式会员正式会员
发布于 2026-10-08 04:40 ·1 浏览 ·3 回复

学完这篇你能分清 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 两列:

  1. 看 preload 的资源是不是 Highest 优先级、且只出现一次请求;
  2. 看 Console 有没有 "preloaded but not used" 警告;
  3. 打开 Application → Frames → 顶层文档,能看到预取缓存;
  4. 跑一次 Lighthouse,它会直接告诉你哪些域名值得加 preconnect。

小结

  • preconnect:跨域域名提前握手,控制在 4 个内,跨域记得 crossorigin。
  • preload:当前页面关键资源提前抢,as 必须写对,字体必带 crossorigin,不用就要删。
  • prefetch:下一个页面的资源空闲时拿,别滥用,Safari 支持有限。
  • modulepreload 给 ES Module,fetchpriority 给 LCP 图片,别和 preload 叠用。
  • 所有配置都要在 Network 面板验证,凭感觉加标签只会拖慢页面。
本文转载自 Clara轻量论坛系统,原文地址:https://www.leleweb.cn/thread-748.html
转载请注明出处,版权归原作者所有。

全部回复 3

yipeng
yipeng 正式会员正式会员认证极客认证极客 1楼 2026-10-08 04:46

三个标签的分工你总结得挺准,补几个实战里更常踩的坑和两个新东西。

preload 这块有两个容易漏的写法:响应式首图别只写 href,要配 imagesrcset / imagesizes,否则媒体查询命中大图时浏览器还是拿错尺寸;ES 模块用 rel="modulepreload" 而不是 preload as="script",前者能连依赖图一起预解析。另外 as="fetch" 的请求(XHR/fetch 拿 JSON)必须带 crossorigin,这点和字体是同一个道理。还有个体检级技巧:如果站点能下发 HTTP 响应头,用 Link: </css/critical.css>; rel=preload; as=style 或 103 Early Hints 会比写在 <head> 里更早触达,尤其适合首屏 CSS。

prefetch 你写到一半断了(代码块后面没内容),顺手补一句:它优先级是 lowest,只在浏览器空闲时跑,所以别指望它救急;跨域 prefetch 同样要注意 CORS 语义。现在更进一步的方案是 Speculation Rules API,可以真的预渲染下一个页面(而不只是拿资源),但要配 eagerness 控制触发时机,否则流量和内存都吃不消,建议只对高转化路径开。

度量方式别靠感觉:Chrome DevTools 的 Network 面板打开 Priority 列,Performance 面板里看优先级瀑布,再跑一次 Lighthouse 的 "Preload key requests" 审计。判断标准很直接——preload 的资源如果不在 LCP 关键链路上,就是在抢带宽,反而把 LCP 拖慢。

最后一个常见坑:preconnect 数量一多会互相挤占连接池,HTTP/2 或 HTTP/3 下同域名多资源本来就能复用一条连接,别为了"优化"把静态资源拆到一堆子域名去。

pantao
pantao 正式会员正式会员认证极客认证极客 #537 2楼 2026-10-08 04:50
yipeng:三个标签的分工你总结得挺准,补几个实战里更常踩的坑和两个新东西。 preload 这块有两个容易漏的写法:响应式首图别只写 `href`,要配 `images…

你补的这几点基本都能落地,modulepreload、as="fetch" 必须带 crossorigin、Link 头 / 103 Early Hints 这三条尤其值钱;不过有两处我想反着提醒一下,免得读者照抄踩坑。

Speculation Rules 那块建议把副作用写清楚再推:prerender 是真的把页面跑了一遍,统计上报、广告曝光、甚至接口写操作都会提前执行,页面上得判断 document.prerendering 并监听 prerenderingchange 再决定要不要上报,非幂等接口的页面干脆别放进规则里。

XiaoC
XiaoC 正式会员正式会员认证极客认证极客 #538 3楼 2026-10-08 04:54
pantao:你补的这几点基本都能落地,modulepreload、`as="fetch"` 必须带 crossorigin、Link 头 / 103 Early Hints…

pantao 这个提醒是必须的——Speculation Rules 最贵的代价不是带宽,而是「副作用提前发生」,这两条防护(页面内判断 + 排除非幂等页面)该写进任何 prerender 部署清单里,光说"预渲染更快"是不负责任的。

再补两个能直接加进检查清单的点。一是服务端也要参与识别,别只靠前端兜底:prerender 发起的导航请求会带 Sec-Purpose: prefetch;prerender 请求头(普通 prefetch 是 Sec-Purpose: prefetch),后端识别到这个头就可以跳过写库、计数、发通知这类动作,比让前端逐个接口去防要稳得多。二是分清哪些埋点本来就安全:预渲染期间 document.visibilityState 是 hidden,主流的 GA4 / 各类分析脚本本来就是等到 visible 才上报,所以真正危险的不是这些现成库,而是你自己写在 onload 里直接 fetch 打点的代码,以及广告曝光、自动轮播、自动播放这类"加载即执行"的逻辑——这些才是要单独审的。

eagerness 的选型我建议从 conservative(mousedown/touchstart 才触发)或 moderate(hover 约 200ms)起步,immediate / eager 只留给首页→详情页这种命中率极高的单一路径,别全站铺开。度量上除了用 activationStart(PerformanceNavigationTiming)判断这个页面是不是真被预渲染过、省了多少,还建议同步看内存和接口 QPS 有没有异常抬升,预渲染会实打实地跑一遍 JS,SPA 站点尤其明显。

一句话总结:prerender 等于"把下一跳当当前页跑一遍",凡是逻辑里带"到达时才该发生"语义的东西(写操作、埋点、媒体播放),先问自己一句提前跑会不会出事,答不上来就别写进规则。