✅ 推荐方案对比
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| IndexedDB + Blob URL | 大量图片、需离线使用 | 容量大、支持二进制、可离线访问 | 实现较复杂 |
| localStorage + Base64 | 少量小图 | 实现简单 | 容量有限(5MB),Base64 体积大 |
| Cache API(Service Worker) | PWA、需要离线资源 | 浏览器原生支持、高效 | 需 Service Worker 环境,不适合动态大量图片 |
| App 原生 WebView 缓存 | 混合 App(如 Flutter、React Native、原生 App) | 性能好、系统级缓存 | 需原生层配合 |
📌 方案一:IndexedDB 缓存图片(推荐)
原理
- 使用
fetch获取网络图片为Blob - 将
Blob存入IndexedDB - 读取时从 IndexedDB 取出
Blob,生成Blob URL用于<img>显示
代码示例
// 1. 初始化 IndexedDB
function openDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open('ImageCacheDB', 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains('
;images')) {
db.createObjectStore('images', { keyPath: 'url' });
}
};
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
// 2. 缓存图片
async function cacheImage(url) {
const db = await openDB();
const tx = db.transaction('images', 'readwrite');
const store = tx.objectStore('images');
// 检查是否已缓存
const getReq = store.get(url);
getReq.onsuccess = () => {
if (getReq.result) {
console.log('图片已缓存,直接使用');
return;
}
// 未缓存,下载并存储
fetch(url)
.then(res => res.blob())
.then(blob => {
store.put({ url, blob });
console.log('图片缓存成功');
})
.catch(err => console.error('缓存失败:', err));
};
}
// 3. 获取缓存图片(返回 Blob URL)
function getCachedImage(url) {
return new Promise((resolve, reject) => {
openDB().then(db => {
const tx = db.transaction('images', 'readonly');
const store = tx.objectStore('images');
const req = store.get(url);
req.onsuccess = () => {
if (req.result && req.result.blob) {
resolve(URL.createObjectURL(req.result.blob));
} else {
reject(new Error('图片未缓存'));
}
};
req.onerror = () => reject(req.error);
});
});
}
// 使用示例
async function displayImage(imgElement, url) {
try {
const blobUrl = await getCachedImage(url);
imgElement.src = blobUrl;
} catch {
// 未缓存,先缓存再显示
await cacheImage(url);
const blobUrl = await getCachedImage(url);
imgElement.src = blobUrl;
}
}
📌 方案二:localStorage + Base64(简单场景)
function cacheImageToLocalStorage(url) {
fetch(url)
.then(res => res.blob())
.then(blob => {
const reader = new FileReader();
reader.onloadend = () => {
localStorage.setItem('img_' + url, reader.result); // Base64 字符串
};
reader.readAsDataURL(blob);
});
}
function getImageFromLocalStorage(url) {
return localStorage.getItem('img_' + url);
}
⚠️ 注意:localStorage 容量有限(5MB),不适合大图或大量图片。
📌 方案三:Cache API(Service Worker)
适用于 PWA 或需要离线能力的场景:
// Service Worker 中
self.addEventListener('fetch', event => {
if (event.request.url.match(/.(jpg|jpeg|png|gif)$/)) {
event.respondWith(
caches.open('image-cache').then(cache => {
return cache.match(event.request).then(response => {
return response || fetch(event.request).then(networkResponse => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
});
})
);
}
});
📌 方案四:混合 App 中的 WebView 缓存
如果你是在
Flutter、React Native、UniApp、原生 App 等环境中使用 H5:
- Flutter:使用
cached_network_image插件 - React Native:使用
react-native-fast-image - UniApp:使用
uni.getImageInfo+ 本地存储 - 原生 WebView:配置 Cookie/Cache 策略,或使用原生层缓存
🔒 注意事项
- 跨域问题:确保图片服务器允许跨域(
Access-Control-Allow-Origin),否则fetch可能失败。 - 内存泄漏:使用
URL.createObjectURL后,在不需要时调用URL.revokeObjectURL()释放内存。 - 清理缓存:提供手动清理缓存的功能,避免占用过多存储空间。
- HTTPS 限制:某些浏览器对非 HTTPS 页面的
IndexedDB或Cache API有限制。
✅ 最佳实践建议
- 少量小图 →
localStorage+ Base64 - 大量图片/离线需求 →
IndexedDB+Blob URL - PWA 项目 →
Cache API+ Service Worker - 混合 App → 使用原生提供的图片缓存库
根据你的具体场景选择合适的方案即可,如有更多细节(如图片数量、是否离线、框架类型),我可以提供更针对性的代码。
首发原创文章,作者:世雄 - 原生数据库架构专家,如若转载,请注明出处:https://idctop.com/article/478116.html



