
如果你是在做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