广告图预加载应优先使用<link rel="preload" as="image">置于<head>,需满足as="image"、静态绝对路径、不与loading="lazy"共用;WebP需JS检测回退;动态场景用new Image()并正确绑定事件顺序。

用 <link rel="preload"> 声明广告图必须写在 <head> 里
广告图如果确定会在首屏或用户进入后极短时间内展示(比如开屏广告、banner位、弹窗主图),就该用 <link rel="preload"> 提前拉取,而不是等 <img> 解析到才发起请求。它不渲染、不占布局,只进缓存,是唯一被浏览器原生支持的“真预加载”方式。
必须满足以下条件才能生效:
-
as="image"缺一不可,否则浏览器当普通资源处理,可能跳过图片特有的缓存策略和解码优化 -
href必须是静态路径,不能含 JS 变量、模板字符串(如"/ads/${id}.webp"会直接 404) - 路径需基于 HTML 文档位置解析;若 HTML 在
/user/profile.html,则href="images/ad.jpg"实际请求的是/user/images/ad.jpg,应改用绝对路径/images/ad.jpg - 不要和
loading="lazy"同时用——后者是推迟加载,逻辑冲突,Chrome 会忽略 preload 或延迟触发
示例:
<head> <link rel="preload" as="image" href="/assets/ads/splash-2x.webp" fetchpriority="high"> <link rel="preload" as="image" href="/assets/ads/banner-mobile.jpg"> </head>
广告图带 WebP 格式时得配 fallback,<picture> 不行,得靠 JS 控制
<link rel="preload"> 不支持格式回退,所以如果你预加载的是 WebP,但要兼容 Safari 13 以下或旧版 Firefox,就不能只靠它——浏览器没下载到 WebP 时,<img src="fallback.jpg"> 还是得发新请求,白预加载。
立即学习“前端免费学习笔记(深入)”;
正确做法是:用 <link rel="preload"> 预载 WebP,再用 JS 检测支持性,动态决定最终 src 赋值:
- 先在
<head>预加载 WebP:<link rel="preload" as="image" href="/ads/main.webp"> - 页面加载后,执行
document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') > -1检测 - 检测通过,就用
new Image()加载 WebP 并监听onload;失败则走 JPG fallback - 别把 fallback 图也
preload,否则浪费带宽——WebP 成功率现在超 95%,只在降级路径里按需加载
需要按用户行为触发广告图预加载?用 new Image(),但顺序不能错
比如用户 hover 到“更多广告”按钮才预载下一批素材,或根据用户地域/设备型号选不同尺寸广告图,就得用 JS 主动控制。此时 new Image() 是唯一选择,但常见错误是事件绑定晚于 src 赋值。
关键操作顺序:
- 必须先绑定
onload和onerror,再赋值src,否则缓存命中时事件同步触发,回调直接丢失 - 赋值后立刻检查
img.complete === true,为true说明已缓存,需立即执行成功逻辑 - 避免在 for 循环里密集
new Image(),浏览器并发请求数通常卡在 6~8 个;建议用 Promise 队列,例如每次最多并发 3 个 - 不要把
Image实例挂到全局变量或长期闭包里,否则内存泄漏风险高;加载完可设img.src = ''断引用
基础封装示例:
const preloadAdImage = (url) => {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = () => reject(new Error(`Ad image load failed: ${url}`));
img.src = url;
});
};
别用 display: none 或 loading="lazy" 伪装预加载
这是最常踩的坑。把广告图写成 <img src="ad.jpg" style="display:none"> 或加 loading="lazy",看起来“提前写了”,其实完全不是预加载:
-
display: none的<img>仍会按默认优先级发起请求,且占 DOM、触发 layout,还可能被 Lighthouse 报“隐藏图片未压缩” -
loading="lazy"是推迟加载,Chrome 默认等到滚动前 500px 才发请求,首屏广告会空白几秒甚至错过曝光时机 -
decoding="async"只影响解码是否阻塞主线程,和“什么时候下载”毫无关系 - 用 CSS background + 负坐标的方式(如
background: url(...) no-repeat -9999px -9999px)已被现代浏览器降权,且无法监听状态、无 fetchpriority 控制,不推荐用于广告这类强时效性资源
广告图的核心诉求是「可控、可测、不干扰首屏」,只有 <link rel="preload"> + 条件性 new Image() 组合能同时满足。



















