react navite图片加载优化、大图卡顿、缓存策略

📅 发布时间:2026/8/16 2:33:29
react navite图片加载优化、大图卡顿、缓存策略 如果你是在做React Native 图片加载优化尤其是「大图卡顿 列表图片 缓存」核心不是单纯换一个 Image 组件而是要同时处理图片尺寸 → 解码 → 内存 → 磁盘缓存 → 列表复用 → 网络加载1. 大图卡顿的核心原因比如服务器返回一张4000 × 3000的 JPEG文件可能只有 2 MB但解码到内存后大约是4000 × 3000 × 4 ≈ 48 MB如果一个 FlatList 同时出现 5 张这样的图片就可能瞬间产生200 MB的 Bitmap/RGBA 内存压力。所以不要把“压缩文件大小”和“降低图片内存占用”混为一谈。最有效的优化通常是让服务端根据显示尺寸返回合适分辨率。2. 首选服务端图片缩放假设 UI 中图片实际只显示屏幕375px 图片150 × 150不要请求4000 × 4000而应该请求类似300 × 300或者根据 DPR150 × 150 × 2 300 × 300如果你的图片 CDN 支持参数可以设计成/image/xxx.jpg?w300h300q80甚至/image/xxx.jpg?w600h600dpr2推荐尺寸策略UI 图片尺寸推荐下载尺寸50×50100×100100×100200×200150×150300×300300×200600×400全屏图片根据设备实际分辨率这通常是 RN 图片性能优化里收益最大的一步。3. React Native 中不要只用Image如果是大量图片、Feed、聊天列表、瀑布流我更推荐考虑expo-image如果你使用 Expoimport { Image } from expo-image; Image source{{ uri: imageUrl }} style{styles.image} contentFitcover cachePolicymemory-disk /缓存策略cachePolicymemory适合图片很容易重复出现但不希望磁盘缓存太多。cachePolicydisk适合希望图片能够跨 App 重启继续使用缓存。cachePolicymemory-disk通常比较适合 Feed / 商品列表 / 社交 App。还可以使用placeholder{blurhash} transition{200}改善用户感知上的加载体验。4. 如果是纯 React Native可以使用Image source{{ uri: url }} style{styles.image} /但需要注意RN Image 自身的缓存行为并不等于一个完整的图片缓存系统。如果你对缓存有比较严格的需求可以考虑expo-imagereact-native-fast-image自己实现 HTTP/CDN 缓存策略不过现在如果是新项目我通常会优先考虑expo-image尤其是 Expo 项目。5. FlatList 才是第二个大坑很多时候用户说“图片加载卡顿”实际上真正的问题是FlatList ↓ 同时创建大量 Image ↓ 大量图片 decode ↓ JS / UI / Native 内存压力 ↓ 掉帧例如FlatList data{data} renderItem{renderItem} keyExtractor{(item) item.id} /可以进一步优化FlatList data{data} renderItem{renderItem} keyExtractor{(item) item.id} initialNumToRender{8} maxToRenderPerBatch{6} windowSize{5} removeClippedSubviews /但这些参数不要盲目调得很小。例如windowSize{2}虽然内存下降但快速滑动时可能频繁创建/销毁内容反而出现闪烁和重新加载。6. 图片组件一定要固定尺寸不推荐Image source{{ uri: url }} style{{ width: 100%, aspectRatio: 1, }} /然后让布局不断计算。更推荐让 FlatList item 的尺寸尽可能明确const IMAGE_SIZE 120; Image source{{ uri: item.image }} style{{ width: IMAGE_SIZE, height: IMAGE_SIZE, }} /尤其是GridAvatar商品列表聊天列表瀑布流明确尺寸可以减少 layout 和渲染的不确定性。7. 缓存策略不要简单理解成“永久缓存”比较合理的是Memory Cache ↓ Disk Cache ↓ Network例如第一次打开 Network ↓ Disk Cache ↓ Memory Cache 第二次进入页面 Memory Cache ↓ 直接显示 App 重启 Disk Cache ↓ 读取 缓存不存在 / 过期 Network对于头像、商品图片、Feed 图片可以采用不同策略。AvatarMemory Disk因为重复率很高。Feed 图片Memory Disk但要限制磁盘缓存规模。一次性大图Disk甚至不长期缓存8. URL 一定要稳定缓存最怕这种情况https://cdn.xxx.com/a.jpg?t123 https://cdn.xxx.com/a.jpg?t456 https://cdn.xxx.com/a.jpg?t789虽然实际是同一张图片但缓存系统可能认为是不同资源。更好的方式https://cdn.xxx.com/image/a.jpg?vabc123内容发生变化的时候才修改版本a.jpg?vabc124这样URL ↓ Cache Key ↓ Image能够稳定复用。9. 大图不要在 RN 里面 resize这是一个很重要的架构问题。❌ 不推荐服务器 5000×5000 ↓ RN 下载 ↓ RN decode ↓ RN resize ↓ 显示 300×300因为最昂贵的事情之一已经发生了5000×5000 decode应该原图 ↓ CDN Resize ↓ 300×300 ↓ RN download ↓ decode ↓ 显示这样能同时减少网络流量decode 时间Bitmap 内存GC 压力UI 卡顿10. 不要 preload 太多大图例如images.forEach(image { Image.prefetch(image.url); });如果images有 100 张100 × 大图可能导致网络请求暴增磁盘缓存暴增内存压力decode 峰值页面真正显示时反而卡更合理的是当前屏幕 前后 12 屏进行有限预加载。11. 一个比较成熟的架构如果是 Feed / 电商 / 社交 App我会建议┌──────────────┐ │ Image CDN │ └──────┬───────┘ │ width/height/q │ ▼ ┌──────────────┐ │ expo-image │ └──────┬───────┘ │ ┌─────────┴─────────┐ ▼ ▼ Memory Cache Disk Cache │ │ └─────────┬─────────┘ ▼ FlatList │ Virtualization │ ▼ Visible Items核心原则就是让“需要显示多少像素”决定“下载多少像素”而不是让原图尺寸决定一切。12. 如果你的问题是“滚动时卡顿”我会按这个优先级排查① 图片是不是远大于显示尺寸 ↓ ② 是否使用了 CDN resize ↓ ③ 图片 decode 是否占用大量内存 ↓ ④ FlatList 是否一次渲染太多 item ↓ ⑤ Image 是否频繁 mount/unmount ↓ ⑥ cache 是否命中 ↓ ⑦ 是否存在 JS thread 阻塞 ↓ ⑧ 是否存在 UI thread / GPU 压力不要第一时间就调windowSize/initialNumToRender。很多项目把 FlatList 参数调了一圈最后发现真正的问题是每个 100×100 的头像 实际上下载的是 3000×3000