html不支持单个标签加载多张图片,预加载需用静态声明或new image()动态创建;前者适用于首屏关键图,后者适合条件触发和状态监听,二者均需注意路径、并发及事件绑定顺序。

HTML 本身不支持单个 <img> 标签加载多张图片,所谓“预加载多张图片”,本质是**并行发起多个独立的资源请求**,必须靠 <link rel="preload"> 声明或 new Image() 实例分别控制。没有“一行代码批量预加载”的语法糖。
用 静态声明多张关键图
这是最推荐的首屏关键图预加载方式,适用于你明确知道哪些图必须最早进缓存的场景(比如 banner、logo、主视觉)。它不渲染、不占 DOM、浏览器能正确识别优先级。
-
rel="preload"必须写在里,且越靠前越好;动态插入无效 - 每张图都要单独写一条
<link>,as="image"缺一不可,否则浏览器无法启用图片专用缓存策略 -
href必须是静态路径,不能含 JS 变量、模板字符串或相对路径歧义(如 HTML 在/user/下,却写href="./assets/hero.jpg") - 可加
fetchpriority="high"(Chrome 101+),对旧版无影响,但别滥用——只给真正首屏急需的图加
示例:
<link rel="preload" as="image" href="/assets/logo.webp" fetchpriority="high"><link rel="preload" as="image" href="/assets/banner.jpg"><link rel="preload" as="image" href="/assets/avatar.png">
用 new Image() 批量触发运行时预加载
当你需要根据条件(如用户 hover、设备像素比、模块加载完成)才开始预加载,或者要监听成功/失败状态时,new Image() 是唯一可控方案。注意并发限制和事件绑定顺序。
- 必须先绑定
onload和onerror,再赋值src,否则缓存命中时事件会同步触发而错过回调 - 检查
img.complete:为true说明已缓存,需立刻走成功逻辑 - 浏览器并发请求数通常为 6~8 个,10 张以上图片建议加队列或分批(如每次
Promise.allSettled控制 4 个) - 别在循环里直接
new Image().src = url—— 这样无法捕获错误,也无法等待完成
基础封装示例:
const preloadImage = (url) => {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = () => reject(new Error(`Failed to load ${url}`));
img.src = url;
});
};
// 批量预加载(带并发控制)
const preloadImages = async (urls, limit = 4) => {
const chunks = [];
for (let i = 0; i
<h3>别踩这些常见坑</h3>
<p>很多人以为加了 <code>loading="lazy"</code> 或把 <code><img></code> 写成 <code>display: none</code> 就算预加载,其实完全相反。</p>
-
loading="lazy"是延迟加载,哪怕加在首屏<img>上,Chrome 也可能等到滚动前 500px 才发请求 -
loading="eager"只是取消懒加载,不等于“提前”;decoding="async"只影响解码时机,和下载无关 - CSS background 伪预加载(如
background: url(...) no-repeat -9999px -9999px)会随页面一起加载,拖慢首屏,且无法监听状态 -
<link rel="prefetch">是为“后续导航”准备的,优先级远低于preload,不适合首屏图
真正难的不是写几行代码,而是判断哪几张图值得预加载、什么时候该切到懒加载、WebP fallback 怎么配才不白忙活——这些得结合 Lighthouse 数据和真实用户网络环境来调,不是堆 <link> 就完事。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











