link rel="preload" 是唯一真正可控、语义明确、Lighthouse 可识别的预加载方式;仅当图片在打开页面后1秒内必然展示、不可滚动触发且尺寸格式固定时才必须使用,典型场景为首屏 banner、logo 等,须置于 head 最顶部、带 as="image"、href 与最终 img src 完全一致。

link rel="preload" 是唯一真正可控、语义明确、Lighthouse 可识别的预加载方式;其他所谓“预加载”要么是懒加载(如 loading="lazy"),要么是伪加载(如 display: none),实际效果相反。
什么时候必须用 link rel="preload"?
只在满足全部三个条件时才加:href 指向的图片,会在用户打开页面后 1 秒内必然展示、无法被滚动触发、且尺寸/格式已固定不变。典型场景:首屏 banner、logo、登录页主视觉图。
- 必须写在
<head>最顶部,不能动态插入,也不能放在<body>里 -
as="image"缺一不可——不写就降级为普通 fetch,缓存不进图片池,解码不走专用管线 -
href必须和最终<img src>完全一致:大小写、斜杠、query 参数都不能差,否则预加载白做 - 支持
fetchpriority="high"(Chrome 109+),旧版忽略无副作用,但别和loading="lazy"同时用——逻辑冲突,浏览器可能直接丢弃 preload
为什么 new Image() 不能随便 new?
它适合运行时判断是否加载(比如 hover 后预载下一页图、按 window.devicePixelRatio 选 @2x 版本),但控制不好就会失败或浪费。
- 顺序铁律:先绑定
onload/onerror,再赋值src;否则缓存命中时事件同步触发,回调直接跳过 - 必须检查
img.complete:为true说明已缓存,需立刻执行成功逻辑,不能等 onload - 并发数硬限制:同域通常最多 6~8 个请求,批量预加载建议用 Promise 队列,每次不超过 4 个
- 别写
new Image().src = url这种单行——失败不可知,也无法await,得封装成 Promise
哪些做法看似预加载,实则无效甚至有害?
最常见的误操作,本质是混淆了“提前下载”和“推迟加载”。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
-
loading="lazy"是延迟加载,不是预加载;哪怕加在首屏<img>上,Chrome 仍可能等到滚动前 500px 才发请求 -
display: none或visibility: hidden的<img>,部分浏览器会推迟 eager 加载,直到元素进入渲染流 -
background-image伪预加载无法监听状态,且不进图片缓存池,复用率极低 - 在
href里写"/assets/${name}.webp"这类模板字符串,会被当字面量请求,大概率 404 白耗流量
构建和部署时最容易被忽略的坑
本地能跑通,上线就失效,往往卡在路径、哈希或 SSR 同步上。
立即学习“前端免费学习笔记(深入)”;
- Webpack/Vite 自动哈希文件名时,
<link rel="preload">的href必须同步更新,硬编码路径必然 404 - SSR 场景下,
<head>中的 preload 标签必须由同一服务端逻辑生成,不能静态写死 - CDN 场景下,
href直接写完整 URL(如https://cdn.example.com/logo.svg),避免路径解析歧义 - WebP 预加载必须选一种格式(推荐 WebP),并在
<img srcset>中确保该格式被实际匹配使用,否则缓存不命中
<link rel="preload">,而是判断“这张图到底值不值得提前拉”。多数项目的问题不在技术实现,而在资源优先级没理清——预加载一张用户根本不会点开的缩略图,不如把带宽留给首屏关键图。


















