图片资源高占用源于内存与网络双超载,需在构建阶段用WebP格式、按pixelRatio适配尺寸、静态图放/static/、动态图限流缓存、禁用Canvas/Base64,并依据服务端信号实施分级加载策略。

图片资源占用高,本质是内存+网络双超载
uni-app 里一张 3MB 的 JPG 图片,在安卓低端机上可能直接吃掉 15MB 内存(解码后按 RGBA 占用),同时阻塞主线程、拖慢滚动帧率。这不是“图太大”的表象问题,而是加载、解码、渲染三个环节同时失控的结果。常见现象包括:列表快速滑动时卡顿掉帧、App 热启动后内存飙升被系统杀进程、H5 页面首次打开白屏时间超 3s。
压缩格式和尺寸必须在构建阶段就确定
别等 runtime 才处理——uni-app 没有运行时图像处理能力,所有优化必须前置。
- WebP 是默认首选:H5 / 微信小程序 / App 全平台支持,同等质量下体积比 JPG 小 30%~50%;AVIF 虽更优但 iOS 小程序暂不支持,慎用
- 尺寸要按设备像素比(
pixelRatio)反推:比如后端返回 1200×800 原图,iOS 设备pixelRatio=3,则实际显示建议用 400×267 尺寸的 WebP,避免拉伸模糊 - 静态图必须放
/static/目录,且路径写死为/static/img/banner.webp;src 动态拼接或从src/引入的图,HBuilderX 构建时不会自动压缩 - 使用
uni-app-plugin-image-compress插件可在构建时批量转 WebP + 自适应尺寸,比手动处理更可靠
动态图加载必须带缓存与并发控制
用户头像、商品图这类网络图,不加管控会瞬间发起几十个请求,尤其在瀑布流中极易触发微信小程序的「单页 10 并发」限制,导致大量请求挂起或失败。
- 强制走本地缓存:用
wx.getFileSystemManager().readFile(小程序)或plus.io.resolveLocalFileSystemURL(App)读取已缓存路径,避免重复下载 - 封装
loadImages工具函数,内部用Promise.allSettled+ 限流器(如每批最多 3 个并发),防止雪崩 - 网络图 URL 必须带版本参数或 hash,例如
https://cdn.com/u/123.jpg?v=20261030,避免 CDN 缓存 stale 数据 - 禁止在
onLoad回调里直接this.$set更新大量图片,改用Object.assign批量赋值,减少响应式开销
Canvas 和 Base64 是内存黑洞,能绕就绕
Canvas 绘制、canvas.toDataURL、Base64 字符串上传,三者都会在内存中保留多份副本:原始 buffer、编码后字符串、解码后 image 对象。在 2GB 内存安卓机上,5 张 2MB Base64 图就可能触发 OOM。
- 选图阶段优先用
sizeType: ['compressed'],而非['original'];需要原图时再单独调用uni.getImageInfo - Base64 必须转临时文件再传:走
uni.uploadFile,而不是 JSON 直传;大图(>1MB)需先压缩再转 Base64 - Canvas 合成海报后,立刻调用
canvas.destroy()(App 端)或手动清空context(H5),否则 canvas 对象常驻内存 - 不要用
v-if切换 Base64 图片,改用opacity+transition复用同一 DOM 节点
真正难的不是“怎么压小”,而是“什么时候该压”——服务端返回的图片宽高字段、CDN 的 Content-Length 响应头、小程序 downloadFile 的 progress 回调,这些信号必须串联起来做分级加载策略。否则光靠前端压缩,只是把问题从内存转移到了网络。











