不能只靠 img.complete 判断成功,因其仅反映当前就绪状态,无法区分缓存命中、加载中或加载失败;404时可能仍为 false,缓存命中时为 true却错过回调,且不提供失败通知能力。

用 new Image() 配合 onload 和 onerror 是唯一可靠、可编程判断预加载是否成功的办法。 其他方式(如仅靠 img.complete、readyState 或 CSS background 加载)无法覆盖缓存命中、跨域失败、404 等全部情况,也不提供失败回调能力。
为什么不能只靠 img.complete 判断成功?
img.complete 只反映「当前是否已就绪」,不区分是缓存命中、加载中还是加载失败。它在以下场景会误判:
- 图片 404 但浏览器尚未触发
onerror(此时complete === false,但你不知道是慢还是失败) - 图片从缓存加载成功(
complete === true),但你没执行成功逻辑,错过时机 - 动态图(如 GIF)可能多次触发
onload,而complete始终为true后续无意义
onload 和 onerror 必须先绑定再赋值 src
顺序错了,缓存命中的图片会直接同步完成,导致事件监听器来不及注册,回调永远不执行:
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
const img = new Image();
// ✅ 正确:先绑事件,再设 src
img.onload = () => console.log('success');
img.onerror = () => console.error('failed');
img.src = '/logo.png';
// ❌ 错误:src 设得太早,缓存图直接跳过 onload
img.src = '/logo.png';
img.onload = () => console.log('never called'); // 可能不执行
并发加载时怎么避免请求被阻塞或失败?
浏览器对同一域名的并发请求数有限制(通常 6~8 个),密集 new Image() 会导致后续请求排队甚至超时:
- 不要在 for 循环里直接 new 多个
Image对象 - 用 Promise 队列控制并发数,例如每次最多 4 个:
Promise.allSettled(promises.slice(0, 4)) - 对失败 URL 做简单退避(如重试 1 次),避免因临时网络抖动误判
- 注意跨域图片:若未配 CORS,
onerror会触发但无法读取img.naturalWidth等属性
预加载后怎么确认图片真能用了?
成功回调里别只打日志,要验证关键可用性:
- 检查
img.naturalWidth > 0,排除透明 GIF 或空图被当成“成功”的情况 - 如果用于替换 DOM 中的
<img>,记得设置img.crossOrigin = 'anonymous'(否则跨域图无法 drawImage) - 避免把
img挂到全局变量或长生命周期闭包里——加载完不用就设img.onload = img.onerror = null,防止内存泄漏(尤其旧版 IE)
真正容易被忽略的是:预加载 ≠ 图片一定能渲染。缓存存在、HTTP 状态 200、onload 触发,这三者都满足,仍可能因 MIME 类型错误(如服务器返回 text/html)、内容损坏或 CORS 限制,导致后续插入 DOM 时显示为空白或报错。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










