资源预加载
preload、prefetch、dns-prefetch 和 preconnect 有什么区别?应该如何使用它们优化资源加载?
核心结论
选择资源提示时,先判断两个问题:
- 资源是当前页面需要,还是后续页面可能需要?
- 已经知道具体资源 URL,还是只知道资源所在的域名?
可以简化记忆为:
这些声明的本质是向浏览器提供额外信息。尤其是 prefetch、preconnect 和 dns-prefetch,浏览器会根据网络状况、设备资源和自身策略决定是否完整执行。
1. Preload:提前发现当前页面的关键资源
preload 的价值不是让资源立即执行,而是解决资源发现得太晚的问题。
例如字体通常要等 CSS 下载、解析并匹配到文字后才能被发现;CSS 背景图也要等样式表解析后才能被发现。把这些当前页面确定会使用的关键资源写入 <head>,浏览器就能更早开始请求。
预加载字体
字体请求使用 CORS 模式,因此字体的 preload 通常需要添加 crossorigin,使预加载请求与之后真正使用字体时的请求模式一致。跨域字体的服务器还必须返回正确的 Access-Control-Allow-Origin 响应头;crossorigin 本身不能绕过 CORS。
预加载首屏关键图片
这更适合通过 CSS 背景、脚本等方式较晚发现的 LCP 图片。如果图片本来就是 HTML 中靠前的 <img>,浏览器的预加载扫描器已经能较早发现它,通常直接在图片上使用 fetchpriority="high" 更简单:
fetchpriority="high" 只是优先级提示,应该只用于少量真正关键的资源,不能替代资源压缩、合理尺寸和 CDN 缓存。
Preload 只负责加载,不负责应用或执行
预加载的 CSS 仍然需要通过样式表链接应用,预加载的经典脚本也仍然需要通过 <script> 执行:
后续请求配置一致时,浏览器会复用已经取得的资源,而不是再次下载。
as 为什么不能省略?
as 告诉浏览器资源的请求目标类型,它会影响:
- 请求优先级;
Accept请求头;- Content Security Policy 的匹配;
- 预加载资源能否被后续请求正确复用。
type 可以进一步声明 MIME 类型。如果浏览器不支持该类型,它可以直接跳过这次预加载;media 则可以避免浏览器在媒体条件不匹配时加载资源。
2. Modulepreload:为 ES Module 准备的预加载
ES Module 默认使用 CORS 模式,并且拥有模块映射、解析和编译等专门的处理流程。对于模块脚本,应优先使用 modulepreload,而不是普通的 preload as="script":
普通 preload 主要是提前获取并缓存响应;modulepreload 还会按照模块脚本的规则处理资源,并将其放入当前文档的模块映射中,供后续执行复用。
3. Prefetch:为后续导航做低成本猜测
prefetch 表示当前页面不需要该资源,但用户接下来很可能需要。浏览器可以降低它的优先级,优先保障当前页面请求:
需要注意:
prefetch是推测性优化,不保证一定发起请求;- 即使已经请求,资源也不保证一直保留到下一次导航;
- 请求仍然受到 HTTP 缓存头、CORS、CSP 和浏览器缓存分区策略影响;
- 预测错误会浪费用户流量,因此只应该预取命中概率较高的资源;
- 它不会自动执行脚本、应用样式,也不会解析被预取 HTML 中的全部子资源。
所以不要把当前页面马上要使用的资源交给 prefetch,否则它可能因为优先级过低而延迟关键内容。
4. DNS Prefetch 与 Preconnect
当具体资源 URL 还不能确定,但已知资源所在域名时,可以提前处理连接阶段。
一次新的 HTTPS 请求通常需要经历:
dns-prefetch只尝试提前完成 DNS 查询;preconnect尝试提前完成 DNS、TCP 和 TLS,但不下载具体资源;- 浏览器在资源受限时可能只完成部分连接准备,或者跳过提示;
preconnect会消耗连接、CPU 和内存,不要为大量不确定域名建立空闲连接;crossorigin用于让连接的凭证模式与后续请求匹配,字体 CDN 是常见场景,但它并不代表服务器已经允许跨域。
5. 为什么 Preload 有时会重复下载?
浏览器复用 preload 时,不是只比较 URL。预加载请求与实际请求至少要在以下方面保持一致:
- URL,包括查询参数和版本号;
- 请求目标类型,即正确的
as; - CORS 请求模式;
- 凭证模式,即是否携带 Cookie 等信息;
- 响应类型及最终选择的资源。
常见问题包括:
响应式图片还要确保 preload 最终选择的 URL 与 <img srcset> 实际选择结果一致,否则也可能下载两张图片。
6. 常见优化误区
误区一:Preload 就是最高优先级
preload 的核心是提前发现。浏览器会根据 as 对应的资源类型分配优先级,还可以参考 fetchpriority,并不是所有 preload 都一律最高优先级。
误区二:Preload 越多越好
preload 不会直接阻塞页面渲染,但它会占用网络带宽和连接资源。预加载过多非关键资源,可能反过来延迟 CSS、LCP 图片等真正关键的请求。
误区三:所有跨域资源都加 crossorigin
是否添加 crossorigin,取决于资源最终的请求模式。盲目添加会导致 preload 与实际请求模式不一致,甚至让原本能展示的跨域图片加载失败。即使添加了它,跨域服务器仍然需要返回正确的 CORS 响应头。
误区四:看到 LCP 图片就一定 Preload
先在 Network 瀑布图中确认资源是否发现过晚。如果 <img> 已经位于 HTML 前部,重复声明 preload 的收益可能很小,优先检查 fetchpriority、图片尺寸、压缩格式和服务端响应时间。
误区五:同时 Preload 多个候选格式
不要同时预加载同一图片的 AVIF、WebP 和 JPEG 版本。浏览器可能支持不止一种格式,从而把多个候选资源都下载下来。应该只预加载页面最终会使用的资源。
7. Webpack 中的资源提示
Webpack 支持通过动态导入的魔法注释生成资源提示:
这是 Webpack 的构建能力,不是 JavaScript 语法本身。不同构建工具的生成策略可能不同,最终应检查构建产物和浏览器 Network 面板,确认提示生成时机、请求优先级以及是否发生重复下载。
实际优化流程
- 通过浏览器 Network 瀑布图确认关键资源是否发现过晚,而不是先批量添加资源提示。
- 对当前页面确定使用、但发现较晚的少量关键资源使用
preload或modulepreload。 - 对关键 LCP 图片谨慎使用
fetchpriority="high",并验证 LCP 是否真实改善。 - 对确定马上访问的第三方域名使用
preconnect,不太确定时使用成本更低的dns-prefetch。 - 只对命中概率高的后续导航资源使用
prefetch。 - 检查控制台中的 unused preload 警告、Network 中的重复请求,并在真实网络环境下对比优化前后的指标。
面试回答模板
preload 用于当前导航确定需要的资源,作用是让浏览器更早发现并请求资源,但不会自动执行或应用资源;它的优先级由 as 对应的资源类型和 fetchpriority 共同影响。prefetch 用于后续导航可能需要的资源,优先级较低,浏览器可以根据运行环境延迟或跳过。preconnect 提前建立到目标域名的连接,dns-prefetch 则只提前进行 DNS 解析。实际使用时要保证 preload 的 URL、as、CORS 和凭证模式与最终请求一致,并通过 Network 瀑布图验证是否真的减少了资源发现和连接耗时。

