预加载不解决缓存更新问题,仅确保资源早进缓存;新图生效需URL变更或服务端缓存头控制,且preload的href必须与img src完全一致、MIME类型显式设置,否则缓存失效。

预加载本身不解决缓存更新问题,它只确保资源“早进缓存”;真正要让新图生效,得靠 URL 变更或服务端缓存头控制。
为什么预加载后图片还是不更新
浏览器对 link rel="preload" 的处理是:把资源下载进缓存,但后续 <img src="/a.jpg"> 是否复用它,取决于两个条件是否严格一致——URL 完全相同、响应的 Content-Type 和实际文件格式也必须匹配。如果服务端悄悄把 /a.jpg fallback 成 PNG,或 CDN 根据 Accept 头返回 AVIF,而 preload 写的是 .jpg,那缓存就失效,<img> 仍会发新请求,且旧图还在缓存里占着位置。
常见表现:Network 面板里看到同一张图被请求两次,一次是 preload,一次是 img;或者明明改了图,页面却一直显示旧版本。
- preload 的
href必须和<img src>的 URL 字符串逐字相同(包括大小写、斜杠方向) - 服务端返回的 MIME 类型不能靠自动推断,需显式设置(如 Nginx 加
types { image/webp webp; }) - 构建工具(Vite/Webpack)若启用了
assetInlineLimit,小图被转成data:URL,而 preload 指向的是原始路径,二者完全不复用
强制刷新图片缓存的可靠做法
当图片内容会动态覆盖(比如用户上传后替换同名文件),仅靠 preload 无济于事。必须让浏览器认为这是“新资源”。最稳的方式是变更 URL:
立即学习“前端免费学习笔记(深入)”;
- 在
src后加时间戳参数:img.src = "/avatar.jpg?t=" + Date.now(); - 用哈希值代替时间戳更优(避免重复请求):
img.src = "/avatar.jpg?v=" + hash;,hash 可从文件内容或服务端 API 获取 - 后端渲染时直接注入带版本号的路径,如
/avatar.jpg?v=2.1.0,配合Cache-Control: max-age=31536000实现长期强缓存
注意:Ctrl+F5 或开发者工具勾选 Disable cache 是调试手段,不能作为线上方案。
preload + fetchpriority="high" 对缓存命中没帮助,但影响加载顺序
fetchpriority="high" 不改变缓存逻辑,只告诉浏览器“这个请求优先级最高”,让它在弱网或资源竞争时排到前面。如果你的图片总在首屏卡住,大概率不是缓存问题,而是请求被 CSS/字体/JS 挤压了。这时加 fetchpriority="high" 才有意义。
- 漏写
as="image"→fetchpriority被忽略,Priority 显示为Low - 写了
as="image"但没fetchpriority="high"→ 多数情况 Priority 是High,但弱网下可能掉到Medium - 两者都写 → Network 面板中 Priority 明确为
Highest,且能进 Chrome 的最高调度队列
srcset 场景下 preload 基本无效
<img src="a.jpg" srcset="a-768w.jpg 768w, a-1200w.jpg 1200w"> 这种写法,浏览器根据设备宽度和 DPR 动态选图。你 preload 其中任意一个尺寸,只要最终选中的不是它,就不会复用缓存——因为 URL 不同,就是两个资源。
真要优化,只有两个选择:
- 服务端 User-Agent 检测 + HTML 模板生成唯一匹配的
link rel="preload"(必须在初始 HTML 中静态写出,不能 JS 插入) - 放弃 preload,直接给
<img>加fetchpriority="high",它能触发浏览器对当前选中的src或srcset子项做高优加载
缓存更新和预加载是两件事:前者靠 URL 或响应头驱动,后者靠声明时机和优先级驱动。混在一起想,容易在 href 路径、MIME 类型、构建配置这些细节上栽跟头。



















