<link rel="preload">必须写as="image",否则浏览器按普通fetch处理,不走图片缓存、不解码、不复用到<img>,即使URL相同也会重复请求;as="image"与fetchpriority="high"缺一不可才能进入Highest优先级队列。

直接用 <link rel="preload"> 是最可靠的方式,其他所谓“伪预加载”基本无效或不可控。
为什么 <link rel="preload"> 必须写 as="image"
漏掉 as="image",浏览器会当成普通 fetch 请求处理:不走图片专用缓存路径、不解码、不复用到后续 <img> 标签。即使 URL 完全一致,<img src="/logo.webp"> 仍会发起第二次请求。
- 服务端返回的
Content-Type必须和as值匹配,比如as="image"对应image/webp,若返回text/html或image/jpeg,缓存失效 - CDN 自动格式协商(如根据
Accept头返回.avif)时,href写死为/hero.webp就会导致类型错配 - Webpack/Vite 构建中启用了
assetInlineLimit,小图被转成data:URL,而href指向的是原始路径,完全无法复用
fetchpriority="high" 在 Chrome 中的实际作用
它不改变缓存行为,只影响网络请求调度优先级。Chrome 101+ 中,只有同时满足 as="image" 和 fetchpriority="high",该请求才会进入 Highest 队列;缺一不可。
- 没加
fetchpriority="high":弱网下可能被字体、CSS 挤到后面,首屏图延迟 300ms+(实测常见) - 加了但没
as="image":fetchpriority被忽略,Network 面板显示 Priority 为Low - 路径含查询参数(如
/banner.jpg?v=20261001)必须和最终<img>的src完全一致,否则缓存不命中
轮播图预加载该用 new Image() 还是 <link rel="preload">
轮播图绝大多数场景必须用 new Image(),因为 <link rel="preload"> 不支持动态路径、不能按需触发、也无法监听加载结果。
立即学习“前端免费学习笔记(深入)”;
- 只预加载当前页 + 相邻 1–2 张(如索引 0、1、2),切到第 5 张时再预加载 4、5、6,避免一次性加载全部造成带宽浪费
- 赋值
src前必须先绑定onload/onerror,否则缓存命中时事件同步触发,回调直接跳过 - 检查
img.complete === true:若为true,说明已缓存,需立刻执行成功逻辑,不能等 onload - 并发控制很关键:浏览器通常限制 6–8 个并发图片请求,轮播预加载建议单次不超过 3–4 个,可用
Promise.allSettled+ 队列节流
哪些做法根本不是预加载,却常被误用
loading="lazy" 是推迟加载,不是提前加载;display: none 或 background-image 伪隐藏只是让元素不可见,不改变资源获取时机,且无加载状态反馈。
-
<img loading="lazy" src="hero.jpg">:Chrome 可能等到滚动前 500px 才发请求,首屏图大概率空白 -
<img src="hero.jpg" style="display:none">:仍参与初始 HTML 解析,和正常<img>一样阻塞渲染,且无法监听失败 -
<div style="background: url(logo.png)"></div>:CSS 加载时机不可控,Lighthouse 不识别,缓存策略也不同于图片资源 -
<link rel="prefetch">:语义是“将来可能用”,优先级极低,不适合首屏关键图
真正难的不是写对一行 <link>,而是确保服务端响应头、构建产物路径、运行时设备判断三者始终对齐——稍有偏差,预加载就退化成白跑一趟请求。



















