预加载
面试速答(30 秒版 TL;DR)
- 预加载(Preload) 是告诉浏览器:这个资源是当前页面很快就要用到的,请尽早拉取。
- 它解决的是 “浏览器发现得太晚” 的问题,常用于关键字体、LCP 图片、首屏脚本、CSS 背景图。
- 最常见写法:
<link rel="preload" href="/fonts/app.woff2" as="font" type="font/woff2" crossorigin />
- 面试里最好顺带区分:
preload:当前页面 很快要用prefetch:未来导航 可能会用
一、心智模型:它为什么有用?
浏览器并不是一开始就知道页面后面会用到哪些资源。
很多资源只有在解析到某个位置时,浏览器才“发现”:
- CSS 背景图,要等 CSS 下载并解析后才知道
- 字体文件,要等 CSSOM 建好并命中字形后才知道
- 动态 import 的模块,要等 JS 运行到对应逻辑才知道
这就会造成一个经典问题:
资源本身很关键,但浏览器发现它的时间太晚。
preload 的作用,就是把“晚发现”改成“早发现”。
先记住这个判断:关键资源如果发现得晚,就要考虑 preload。
二、它最适合解决哪几类场景?
1. 首屏字体
字体常常属于“视觉上很关键,但发现得偏晚”的典型资源。
<link rel="preload" href="/fonts/app.woff2" as="font" type="font/woff2" crossorigin />
2. LCP 图片
比如首页 Hero 图、商品主图、文章头图。如果这张图就是 LCP 元素,提前预加载通常比盲目懒加载更合理。
<link
rel="preload"
as="image"
href="/images/hero.webp"
imagesrcset="/images/hero-800.webp 800w, /images/hero-1600.webp 1600w"
imagesizes="100vw"
/>
3. CSS 背景图
背景图不会像 <img> 一样在 HTML 里直接暴露给浏览器,往往发现得更晚。
<link rel="preload" as="image" href="/images/banner-bg.webp" />
4. 首屏关键脚本
如果某段脚本虽然不是阻塞解析的同步脚本,但很快就要执行,可以考虑预加载后再配合正常的脚本引用。
三、preload、prefetch、modulepreload 怎么区分?
这是这一题最常见的扩展追问。
| 能力 | 用途 | 资源属于谁 | 时机 |
|---|---|---|---|
preload | 当前页面马上要用 | 当前导航 | 尽早拉取 |
prefetch | 未来可能会用 | 下一次导航或低优先级未来资源 | 浏览器空闲时 |
modulepreload | 提前拉取 ES Module 及其依赖 | 当前页面模块图 | 模块执行前 |
推荐答法:
preload是现在就要。prefetch是以后可能要。modulepreload是给 ES Module 体系准备的更专项能力。
如果面试官只问 preload,你把 prefetch 区分出来,答案就会更完整。
四、写 preload 时最容易踩的点
1. as 不能乱写
as 不只是注释,它会影响浏览器如何给资源分类、优先级怎么分配、缓存能不能正确复用。
常见值包括:
as="style"as="script"as="font"as="image"as="fetch"
如果 as 写错,可能出现:
- 资源优先级不符合预期
- 响应缓存无法按正确类型复用
- 浏览器把它当成“预加载了但没真正用上”
2. 字体常常要配 crossorigin
字体文件即使同源,也常按跨域取用规则处理。工程里最稳妥的做法通常是把 crossorigin 一并写上。
3. 预加载不等于执行
很多人误以为:
preload了 JS,就等于脚本已经执行preload了 CSS,就等于样式已经生效
这都不对。
preload 只是 提前下载,真正生效还要靠正常消费它的标签或逻辑。
例如:
<link rel="preload" href="/app.js" as="script" />
<script defer src="/app.js"></script>
上面这个流程是:
- 浏览器先把
/app.js下载好 - 真正执行仍然发生在
<script>阶段
五、为什么说它不是越多越好?
因为 preload 本质是在提高资源优先级。优先级一抬高,就会去抢带宽、抢连接、抢调度机会。
如果你把很多非关键资源也标成 preload,就会出现:
- 真正关键的资源被带宽竞争拖慢
- 首页请求瀑布变得更拥挤
- 浏览器报警“预加载了但很久没用到”
一个很实用的判断标准是:
这个资源如果不提前请求,是否真的会拖慢当前页面关键路径?
如果答案并不明确,就别急着加。
六、一个更完整的页面示例
<head>
<link rel="preload" href="/fonts/app.woff2" as="font" type="font/woff2" crossorigin />
<link rel="preload" href="/images/hero.webp" as="image" />
<link rel="preload" href="/main.css" as="style" />
<link rel="stylesheet" href="/main.css" />
<script defer src="/app.js"></script>
</head>
这里的意图是:
- 字体:提前下载,避免首屏文案等待字体
- Hero 图:尽快到达,争取更好的 LCP
- 主样式:尽早拿到,缩短渲染等待
但如果这个页面还有一堆评论区脚本、推荐位图片、图表库,它们通常就不该一起 preload。
七、典型题与标准答法
Q1:什么是预加载?
答法:
预加载就是通过 rel="preload" 告诉浏览器,某个资源是当前页面很快就要用到的关键资源,请尽早拉取。它主要解决浏览器“发现资源太晚”的问题,常见于字体、LCP 图片、背景图和关键脚本。
Q2:它和 prefetch 有什么区别?
答法:
preload 面向当前页面关键路径,优先级更高;prefetch 面向未来导航,通常在浏览器空闲时做低优先级获取。一个是“现在就要”,一个是“后面可能要”。
Q3:为什么 preload 不能乱加?
答法:
因为它会提高资源调度优先级。如果把一堆非关键资源也标成高优先级,就会造成带宽竞争,反而拖慢真正的关键资源,属于典型的过度优化。
Q4:preload 了 JS,是不是脚本就执行了?
答法:
不是。preload 只负责提前下载,真正执行仍然依赖后续的 <script> 或模块消费流程。
八、常见误区
-
误区 1:把
preload当成“无脑加速开关”。 它只适合关键路径资源。 -
误区 2:
as随便写。 这会影响优先级和缓存复用。 -
误区 3:首屏外资源也一律
preload。 这通常是在制造带宽竞争。 -
误区 4:把“提前下载”和“立即执行”混为一谈。 预加载不等于执行、不等于渲染完成。
九、速记要点
preload= 当前页面马上要用,尽早下载。- 核心价值:解决关键资源发现过晚。
- 典型对象:字体、LCP 图片、背景图、关键脚本。
as要写对,字体常配crossorigin。- 不是越多越好,避免关键资源被错误竞争。