必须用link rel="preload"预加载首屏关键图(如banner、logo),且url构建时已知;需写在最前、as="image"、href静态一致,否则退化为低优先级fetch。

图片预加载不是“加个属性就变快”,它只在特定场景下真正起效;用错地方反而拖慢首屏、浪费带宽。
什么时候必须用 link rel="preload"
当你有明确的首屏关键图(比如 banner、logo、登录页主视觉),且这张图的 URL 在构建时就能确定,link rel="preload" 就是唯一推荐方式。它让浏览器在解析 阶段就发起请求,比等 DOM 解析到 <img> 标签早 300–600ms,直接抬高 LCP 指标。
-
as="image"缺一不可——漏掉就退化成普通 fetch,Network 面板里 Priority 显示为 Low - href 必须是静态路径,不能含
${name}或 JS 变量,否则 404 - 必须写在
最前面,动态插入(如document.createElement('link'))完全无效 - 和后续
<img src>的 URL 必须完全一致(大小写、斜杠、查询参数都不能差)
什么时候该用 new Image() 而不是 preload
当你需要根据运行时条件决定是否加载:比如 hover 后预载下一页缩略图、按 window.devicePixelRatio 加载 @2x 版本、或用户进入某个模块才触发预加载。
- 必须先绑定
onload/onerror,再赋值src,否则缓存命中时事件直接同步触发,回调被跳过 - 要检查
img.complete:为 true 说明已缓存,需立刻执行成功逻辑 - 避免密集循环
new Image()——浏览器并发请求数通常只有 6~8 个,建议用 Promise 控制并发(如每次最多 4 个) - 不要用
new Image().src = url简写,它无法捕获失败,也无法链式等待
为什么 loading="lazy" 和 display: none 不是预加载
它们名字里带“懒”或“隐藏”,但行为完全相反:loading="lazy" 是推迟加载,Chrome 会等到滚动前 500px 才发请求;display: none 的 <img> 仍要等 HTML 解析到那一行才开始下载,不解决首屏延迟问题。
-
loading="eager"只是默认行为,不等于“提前” -
decoding="async"只影响解码时机,和下载无关 - CSS
background-image+ 负偏移伪预加载,既无加载状态监听,又可能因 CSS 优先级低而被延迟 - 所有这些方式都无法被 Lighthouse 识别为“关键资源提前获取”,性能报告里照样报 LCP 延迟
最容易被忽略的一点:预加载本身不保证渲染,它只确保资源进缓存。如果你 preload 了 /assets/hero.webp,但页面里 <img src="hero.webp"> 少了个斜杠,浏览器还是会重新请求一次——缓存白做,LCP 也救不回来。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











