图片预加载需主动声明而非依赖属性,核心方式有二:一是用<link rel="preload" as="image">提前加载首屏关键图,须绝对/根相对路径且置于<head>;二是用new Image()运行时条件加载,需先绑定事件再赋值src并控制并发。

图片预加载不是靠加个属性或放个标签就自动生效的,它必须明确告诉浏览器“这张图马上要用”,否则浏览器按默认策略处理——该懒加载的继续懒,该等渲染的继续等。
用 <link rel="preload"> 提前声明首屏关键图
这是最轻量、最可控的方式,只适用于你**100%确定会在首屏或交互初期立即展示**的图,比如 banner、logo、登录页主视觉。
-
as="image"必须写,缺了它浏览器当普通 fetch 处理,无法复用图片缓存和解码策略 - 路径必须是绝对路径或根相对路径(如
/assets/hero.webp),不能写./images/hero.jpg—— HTML 在子目录下时会 404 -
fetchpriority="high"对 Chrome 109+ 有效,能压过部分 CSS/JS 请求;旧版忽略,无副作用 - 必须放在
<head>里,且越早越好;放在<body>中会被浏览器直接忽略 - 别和
loading="lazy"同时用——逻辑冲突,preload 可能被静默丢弃
用 new Image() 实现运行时条件预加载
当你需要根据用户行为、设备特性或状态决定是否加载时(比如 hover 商品卡片后预载详情大图、滑动轮播到第 3 页时预载第 4 页缩略图),Image 是唯一可控的选择。
- 顺序不能错:先绑定
onload/onerror,再赋值src;否则缓存命中时事件同步触发,回调直接跳过 - 检查
img.complete:如果为true,说明已缓存,需立刻执行成功逻辑,不能等 onload - 避免密集
new Image():浏览器同域并发请求数通常只有 6~8 个,建议用 Promise 队列控制(例如每次最多 4 个) - 别写
new Image().src = url这种一行式——失败不可知,也无法 await 或链式处理
别把 loading="lazy" 或 display: none 当预加载用
这是最常踩的坑。设置 loading="lazy" 是推迟加载,不是提前加载;Chrome 会等到滚动前约 500px 才发起请求,完全违背预加载目标。
立即学习“前端免费学习笔记(深入)”;
-
loading="eager"只是“不懒”,不等于“提前”;它仍要等 DOM 解析到对应<img>标签才开始请求 -
display: none或visibility: hidden会导致部分浏览器推迟 eager 加载,直到元素进入渲染流 - CSS background 预加载(如
background: url(...) no-repeat -9999px -9999px)虽可行,但会随页面一起加载,挤占首屏带宽,且无法监听完成状态
验证预加载是否真正生效的三个硬检查点
光写对代码不等于起效,浏览器不会报错,只会默默失效。
- 打开 DevTools → Network 标签页,筛选
type: image,确认预加载请求出现在 HTML 解析早期(时间线靠左),且状态码是 200 或 304 - 对比
<link rel="preload">的href和最终<img src>(或srcset中实际匹配的那项)——必须完全一致,包括大小写、斜杠、query 参数 - 构建工具做了文件哈希(如
logo.a1b2c3.webp)?preload 的 href 必须同步更新,硬编码logo.webp就是白忙一场
真正难的不是写几行 preload 或 new Image,而是判断哪张图值得预加载、在哪个时机触发、以及如何确保它和后续真实使用的 URL 完全对得上——这三个判断错了,代码写得再漂亮也白搭。



















