link rel="preload" 不按顺序加载,因其并行发起且由浏览器按启发式算法调度;真要控制节奏需用 js 动态创建 image 实例并串行监听 onload 事件。

预加载本身没有“顺序”可调——link rel="preload" 是并行发起的,浏览器不保证执行先后;真要控制加载节奏,得靠 JS 动态插入 img 或串行触发 Image 实例。
为什么 link rel="preload" 不按顺序加载
link rel="preload" 的作用是提前声明资源,让浏览器在空闲时尽早获取,但它不排队、不阻塞、不串行。即使你在 里按 A→B→C 的顺序写三个 <link rel="preload" as="image" href="a.jpg">,浏览器仍可能因并发限制、缓存状态、网络调度策略等原因,让 B 先完成、A 后到。
- 所有
preload请求都归入同一高优先级队列,浏览器按自身启发式算法分发,不读取 HTML 书写顺序 -
fetchpriority="high"只影响单个请求在网络层的调度权重,不改变多个preload之间的相对时机 - 如果 a.jpg 已缓存,它可能瞬间完成;而 b.jpg 正在 DNS 查询或 TLS 握手,就会明显滞后——这和“顺序”无关,是资源状态差异
用 new Image() 实现可控的串行预加载
当你需要严格确保图 A 完全加载(含解码)后再加载图 B,必须放弃声明式预加载,改用 JS 主动管理。核心是:监听 onload,成功后才创建下一个 Image 实例。
- 必须先绑定
onload和onerror,再赋值src,否则缓存命中时事件直接跳过 - 检查
img.complete:若为true,说明已缓存,应立即执行回调,不等 onload - 避免在循环中密集 new Image()——浏览器并发连接数有限(通常 6 个),建议用递归或 Promise 队列控制节奏
function preloadSequential(urls, index = 0) {
if (index >= urls.length) return;
const img = new Image();
img.onload = () => preloadSequential(urls, index + 1);
img.onerror = () => preloadSequential(urls, index + 1); // 失败也继续下一张
img.src = urls[index];
}
DOM 插入顺序才是加载顺序的底层锚点
如果你最终要把这些图片渲染出来,且要求“视觉呈现”与“加载完成”强一致(比如轮播图首帧必须最优先),那么最可靠的方式不是预加载,而是控制 img 元素的 DOM 插入时机:
- 先
document.createElement('img')+ 赋src+appendChild(),触发立即加载 - 后续图片用
setTimeout、requestIdleCallback或IntersectionObserver延迟插入 - 注意:不要在
DOMContentLoaded前大量插入img,否则会阻塞 HTML 解析,反而拖慢首屏 -
loading="eager"是默认行为,显式写上更清晰;但别给它加fetchpriority="low"——Chrome 会忽略,Safari/Firefox 直接无视
容易被忽略的关键点
很多人试图用 CSS background-image 或 display: none 的 img 标签“伪预加载”,这在现代浏览器中基本失效:
- CSS background 图片加载时机不可控,常被延迟到样式计算完成甚至首次绘制前,且不参与 LCP 计算
-
display: none的img仍会按 HTML 顺序加载,只是不渲染——既没提速,也没顺序保障 -
loading="lazy"和预加载完全相反,设了它,preload的提示也可能被浏览器降级处理
真正能落地的顺序控制,只发生在两个层面:HTML 结构顺序(静态)、JS 插入时机(动态)。其他全是表面功夫。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











