link rel="preload"是唯一真正符合预加载语义的原生方案,必须静态写在中后、前,且需严格匹配as属性(如as="image")、路径完全一致,否则降级为low优先级fetch或静默失效。

link rel="preload" 是唯一真正符合“预加载”语义的 HTML 原生方案,但它不是往 <img> 上加属性,而是必须写在 里的一条独立声明——用错位置、漏写关键字段,它就完全不生效。
必须写在 且不能动态插入
浏览器只在 HTML 解析阶段识别 link rel="preload",一旦开始构建 DOM 或 JS 开始执行,再用 document.createElement('link') 插入就无效。常见失败场景包括:
- 把
<link rel="preload">放在里(哪怕紧贴) - 在 Vue 的
mounted、React 的useEffect里动态创建并 append 到head - 通过服务器模板(如 EJS、Nunjucks)在运行时拼接 href,但实际输出仍是静态 HTML —— 这可以,但前提是最终 HTML 源码里真有那行标签
as="image" 是硬性要求,不是可选项
漏写或写错 as 值,会导致浏览器降级为普通 fetch 请求,Priority 变成 Low,Network 面板里 Initiator 显示为 parser 而非 preload。验证是否生效,必须同时满足:
- Network 面板 Filter 输入
Initiator: preload,能看到对应图片请求 - 该请求的
Priority列显示为Highest(as="image")或High(as="style") - 如果 Priority 是
Low,90% 是as缺失或类型错配(比如写成as="fetch")
路径必须绝对或根相对,且不能含 JS 变量
href 是纯静态字符串,浏览器不会解析其中的模板语法或变量。典型错误有:
-
href="./images/hero.jpg":HTML 文件若在/user/profile.html,实际请求路径会变成/user/images/hero.jpg,404 -
href="/assets/${name}.webp":浏览器字面量请求,发的是/assets/%24%7Bname%7D.webp -
href="hero.jpg?v=1"和后续<img src="hero.jpg?v=2">并存:缓存不复用,等于白预加载
正确写法是 href="/assets/hero.webp"(推荐)或 href="../assets/hero.webp"(仅当确认 HTML 与资源目录层级固定)。
别对已存在的 <img src> 重复加 preload
浏览器会自动发现并加载 <img src="xxx">,再额外加一条 <link rel="preload" as="image" href="xxx"> 不仅冗余,还可能因 URL 大小写、查询参数差异导致两次请求。真正需要 preload 的,是那些浏览器“发现太晚”的资源:
- CSS 中的
background-image -
<picture></picture>里关键的<source></source>(尤其 WebP fallback 场景) - 内联 SVG 中引用的外部图片
对于普通 <img>,优先用 fetchpriority="high"(Chrome 101+),或确保它出现在 HTML 早期、不被 JS 动态插入。
最易被忽略的一点:preload 只负责下载进缓存,不触发渲染;它和 loading="lazy" 是反向操作,两者共存就是自相矛盾。如果你看到页面首屏图仍延迟出现,先检查 Network 面板里那张图的 Initiator 和 Priority,而不是调 new Image() 补救。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











