图片预加载分声明式(link rel="preload")和运行时式(new image())两种:前者需在head中静态声明、as="image"、绝对路径,适用于首屏确定资源;后者用于条件加载,须先绑事件再赋src、检查complete、控并发。

图片预加载不是“加个属性就完事”,它分两种根本不同的流程:静态声明式(link rel="preload")和运行时控制式(new Image())。选错方式,轻则无效,重则拖慢首屏。
用 link rel="preload" 声明首屏关键图
这是唯一能真正“提前”获取资源、且被 Lighthouse 认可的方式,只适用于你**100%确定这张图会在首屏或交互初期立即使用**的场景(比如 banner、logo、登录页主视觉)。
- 必须写在
里,越早越好;动态插入(比如 JS 创建后 append)完全无效 -
as="image"缺一不可 —— 没它,浏览器当普通 fetch 处理,不走图片缓存/解码策略 -
href必须是静态路径,不能含 JS 变量、模板语法(如"/assets/${name}.webp"),否则直接 404 - 相对路径基于 HTML 文件位置解析,常见错误是写成
./images/hero.jpg,但 HTML 在/user/profile.html下,应改用绝对路径/images/hero.jpg -
fetchpriority="high"在 Chrome 101+ 有效,能抬高请求优先级;旧版忽略,无副作用
用 new Image() 实现条件化预加载
当你需要根据用户行为、设备特性或状态决定是否加载时(比如 hover 后预载下一页缩略图、按 window.devicePixelRatio 加载 @2x 版本),Image 是唯一可控的选择。
- 顺序不能错:先绑定
onload和onerror,再赋值src;否则缓存命中时事件同步触发,回调直接跳过 - 必须检查
img.complete:为true说明已缓存,需立刻执行成功逻辑,不能等 onload - 避免密集
new Image():浏览器并发请求数通常只有 6~8 个,批量预加载建议加队列或限制并发(例如每次最多 4 个) - 别用
new Image().src = url简写 —— 它无法捕获失败,也无法链式等待
别把 loading="lazy" 或 display: none 当预加载用
loading="lazy" 是推迟加载,不是提前加载。哪怕你给首屏 <img> 显式加上它,Chrome 仍可能等到滚动前 500px 才发请求 —— 和预加载目标完全相反。
-
loading="eager"只是“不懒”,不等于“提前”;它仍是 DOM 渲染触发的常规加载时机 -
decoding="async"只影响解码时机(防主线程卡顿),和下载时机无关 -
display: none或 CSS background 伪隐藏,无法监听加载状态,失败不可知,也不受浏览器资源调度优化 - 如果发现某张图“怎么还没出来”,先查是不是误用了
loading="lazy",而不是急着加预加载
最易被忽略的点:WebP 预加载必须配 fallback。用 link rel="preload" 加载 .webp 时,若浏览器不支持,它不会自动退到 .jpg —— 你得在后续 <img> 或 <picture></picture> 中显式提供降级路径,否则就是白加载。











