前端图片加载该用 <img> 还是 new Image()?
更新: 6/6/2026 字数: 0 字 时长: 0 分钟
这两者经常被混淆,但用对场景能让页面更流畅、代码更简洁。
板块一:浏览器加载图片的底层机制
要搞懂两者区别,先得明白浏览器是怎么把一张图片「搬」到屏幕上的。整个过程其实分三步:
第一步:发起网络请求 浏览器拿到图片地址(URL)后,向服务器发送一个请求:「请把这张图给我」。这一步走的是网络,耗时取决于图片大小和网速。
第二步:下载图片数据 服务器把图片的二进制数据一点点传回来。此时图片还只是「一堆字节」,并不能直接看。
第三步:解码并渲染 浏览器把下载好的数据解码(把压缩的 JPG/PNG 还原成像素)、计算尺寸,再把它画(渲染)到页面对应位置上。到这一步,用户才真正「看见」图片。
关键认知:下载 ≠ 显示 一张图片可以「已经下载到浏览器里了」,但「还没有显示在页面上」。这两件事是分开的——这正是理解
<img>和new Image()区别的核心。
还有一个隐藏帮手:浏览器缓存 同一张图片第一次加载后,浏览器会把它存进缓存。下次再用到相同 URL 的图片时,就不必重新走网络,直接从缓存里秒取。new Image() 的预加载技巧,本质就是在利用这套缓存机制。

板块二:两者的本质差异
这是全篇最关键的一节。一句话概括:
<img>是「页面上的图片元素」,看得见、会上屏;new Image()是「内存里的图片对象」,默认看不见、不上屏。
| 对比维度 | <img>(HTML 标签) | new Image()(JS 创建的对象) |
|---|---|---|
| 本质 | 写在页面里的真实 DOM 元素 | JS 在内存中 new 出来的 HTMLImageElement 对象 |
| 是否显示在页面上 | 会,默认就显示 | 不会,除非你手动把它 append 到页面 |
| 触发图片下载 | 设置 src 后自动下载 | 设置 src 后同样会下载(并写入缓存) |
| 主要用途 | 直接展示图片给用户看 | 后台预先下载、监听加载状态、做逻辑控制 |
| 写法 | <img src="a.jpg"> | const img = new Image(); img.src = "a.jpg"; |
补充说明(划重点): 其实 new Image() 创建出来的,和页面里的 <img> 是同一种东西——都是图片元素对象。区别只在于:<img> 一出生就「站在页面上」,而 new Image() 默认「待在内存里、不露面」。正因为它不上屏,所以特别适合用来「偷偷把图片先下载好」。

板块三:什么时候 new Image() 更合适?
new Image() 的杀手锏是「先下载、不显示」。凡是需要提前准备图片、或对加载过程做控制的场景,它都更合适。
1. 图片预加载(最经典用法) 比如轮播图、相册下一张、鼠标悬停才显示的大图。你可以在用户还没看到之前,用 new Image() 把图片悄悄下载进缓存。等真正要显示时,因为缓存已命中,图片瞬间出现、不会白屏闪烁。
// 预加载下一张图片,提前写入缓存
const img = new Image();
img.src = "next-banner.jpg";2. 需要监听加载完成 / 失败new Image() 能精确监听 onload(加载成功)和 onerror(加载失败),方便你「加载完再显示」「失败了换备用图」。
const img = new Image();
img.onload = () => console.log("图片下载好了,可以显示了");
img.onerror = () => console.log("加载失败,换默认图");
img.src = "photo.jpg";3. 纯逻辑用途,不需要立刻上屏 比如提前探测某张图能不能正常加载、获取图片真实宽高、做埋点统计等。这些只需要图片「在内存里」,不需要呈现给用户,用 new Image() 最干净。
一句话:「先下后用、要监听、不急着显示」→ 用
new Image()。

板块四:什么时候直接用(甚至只用)<img>?
绝大多数日常场景,直接写 <img> 才是正解,不要画蛇添足。
1. 就是要在页面上展示一张图 内容图、头像、Logo、商品图……只要目的是「让用户看到」,直接写 <img> 即可,浏览器会自动下载并显示,简单可靠。
<img src="avatar.jpg" alt="用户头像">2. 想要代码简单、可维护<img> 是声明式写法,HTML 里写清楚就行,不用写一堆 JS 逻辑。能用一行标签解决的,就别用脚本绕弯。
3. 想用浏览器原生的优化能力 现代 <img> 自带很多「免费福利」,直接写属性就能用:
loading="lazy":原生懒加载,图片快滚到可视区域时才加载,省流量、提速度,无需任何 JS。srcset/sizes:根据屏幕自动选择合适清晰度的图片。decoding="async":异步解码,避免卡住页面渲染。
<img src="banner.jpg" loading="lazy" alt="活动横幅">重要提醒:别用
new Image()去做<img>本来就能做的事。 很多新手为了「懒加载」手写一堆new Image()逻辑,其实现在一个loading="lazy"属性就够了,又简单又高效。
一句话:「就是要显示、追求简单、想吃浏览器原生优化」→ 直接用
<img>。

一张表帮你快速决策
| 你的需求 | 推荐方案 |
|---|---|
| 页面上直接展示图片 | <img> |
| 图片懒加载(滚动到才加载) | <img loading="lazy"> |
| 提前预加载下一张/即将用到的图 | new Image() |
| 监听图片加载成功 / 失败 | new Image() + onload/onerror |
| 探测图片是否可用、获取尺寸等纯逻辑 | new Image() |
| 兼顾展示 + 加载控制 | 先 new Image() 预载,再用 <img> 展示 |
最终心法:默认用
<img>(声明式、简单、有原生优化);当你需要「在显示之前对加载过程做控制」时,才请出new Image()。两者不是对立,而是分工。
文档已覆盖你要求的全部维度——底层加载机制、本质差异、new Image() 适用场景、<img> 适用场景,并为每个板块配齐了统一卡通科普风、中文内容的配图及可直接复用的生成提示。如果需要,我可以把它整理成排版精美的飞书文档或 HTML 网页,方便沉淀到你的开发学习资料库。