上一篇
h5实现网络缓存图片
- 行业动态
- 2025-05-16
- 8
通过Service Worker缓存图片:注册worker后,在install事件中缓存图片资源,拦截fetch请求时优先返回缓存,未命中则获取网络资源并缓存
H5实现网络缓存图片的核心技术与实践指南
HTML5缓存机制
HTML5提供了多种客户端缓存方案,其中与网络图片缓存相关的核心技术包括:
- Application Cache(应用缓存):通过manifest文件预定义缓存资源
- Service Worker:通过JavaScript实现异步缓存控制
- LocalStorage/IndexedDB:键值对存储(适合少量数据)
- Cache API:配合Service Worker使用的缓存接口
缓存方案 | 支持浏览器 | 离线能力 | 更新控制 | 存储容量 |
---|---|---|---|---|
Application Cache | IE10+/Chrome/Firefox | 完全离线 | 自动更新 | 约5MB |
Service Worker | IE11+/Chrome/Firefox/Safari | 完全离线 | 手动控制 | 无限制 |
LocalStorage | 全平台现代浏览器 | 无 | 无 | 5-10MB |
IndexedDB | 全平台现代浏览器 | 无 | 无 | 500MB+ |
Application Cache实现图片缓存
创建缓存清单文件(manifest)
CACHE MANIFEST # v1.0 2023-08-01 CACHE: /images/logo.png /images/banner.jpg /css/style.css /js/app.js NETWORK:
HTML引用manifest文件
<!DOCTYPE html> <html lang="zh-CN" manifest="cache.manifest"> <head> <meta charset="UTF-8">图片缓存示例</title> </head> <body> <img src="images/logo.png" alt="Logo"> <img src="images/banner.jpg" alt="Banner"> </body> </html>
工作原理说明
- 首次加载时,浏览器按manifest文件缓存资源
- 后续访问直接使用本地缓存资源
- 更新manifest版本号可触发缓存刷新
Service Worker实现智能缓存
注册Service Worker
if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js') .then(reg => console.log('SW注册成功:', reg)) .catch(err => console.error('SW注册失败:', err)); }
Service Worker核心代码(sw.js)
const CACHE_NAME = 'image-cache-v1'; const IMAGE_URLS = [ '/images/logo.png', '/images/banner.jpg' ]; self.addEventListener('install', event => { event.waitUntil( caches.open(CACHE_NAME) .then(cache => cache.addAll(IMAGE_URLS)) ); }); self.addEventListener('fetch', event => { if (event.request.url.endsWith('.png') || event.request.url.endsWith('.jpg')) { event.respondWith( caches.match(event.request) .then(response => response || fetch(event.request)) ); } });
缓存策略对比表
策略类型 | 适用场景 | 更新机制 | 性能表现 |
---|---|---|---|
Cache-First | 静态资源(图片/CSS/JS) | 手动版本控制 | 最佳加载速度 |
Network-First | 动态数据(API响应) | 实时获取 | 数据及时性高 |
Stale-While-Revalidate | 平衡型需求 | 后台静默更新 | 兼顾速度与时效 |
缓存更新与版本管理
Application Cache更新流程
- 修改manifest文件内容(如版本号)
- 浏览器检测到manifest变化后重新下载资源
- 旧缓存保留直到新缓存完全可用
Service Worker更新策略
// sw.js中监听update事件 self.addEventListener('updatefound', event => { const newWorker = event.newRegistration; newWorker.onupdatefound = function() { if (navigator.serviceWorker.controller) { // 有旧版本在运行,提示用户刷新 console.log('发现新版本,请刷新页面'); } }; });
强制刷新缓存方法
// 通过重新注册Service Worker实现强制更新 navigator.serviceWorker.getRegistration().then(reg => { if (reg) { reg.unregister().then(() => { window.location.reload(); }); } });
性能优化与异常处理
缓存容量控制
// 使用IndexedDB存储大文件路径 const db = new Dexie('ImageCacheDB'); db.version(1).stores({ images: '++id,url,timestamp' }); // 缓存前检查存储空间 navigator.storage.estimate().then(est => { if (est.usage < est.quota 50 1024 1024) { // 剩余50MB空间 cache.add(url); } else { console.warn('存储空间不足,跳过缓存'); } });
缓存失效处理机制
fetch(url) .then(response => { if (!response.ok) throw new Error('网络响应异常'); return caches.open(CACHE_NAME).then(cache => { cache.put(url, response.clone()); return response; }); }) .catch(err => { return caches.match(url).then(cachedResponse => { if (cachedResponse) return cachedResponse; throw new Error('网络故障且无缓存'); }); });
跨域缓存解决方案
<!-设置CORS响应头 --> Access-Control-Allow-Origin: Access-Control-Max-Age: 3600
// Service Worker处理跨域请求 event.respondWith( fetch(event.request).then(response => { // 克隆可跨域的响应对象 return response.clone(); }).catch(() => caches.match(event.request)) );
实战案例分析
案例:电商商品图片缓存优化
需求分析:
- 商品列表页大量图片需要快速加载
- 用户频繁切换分类时避免重复加载
- 支持离线查看最近浏览的商品
实施方案:
- 使用Service Worker实现三级缓存:
- L1:内存缓存(当前会话)
- L2:Service Worker缓存(会话间持久)
- L3:IndexedDB存储(长期保存)
- 采用Stale-While-Revalidate策略:
- 优先显示缓存图片(L1->L2->L3)
- 后台静默更新最新图片版本
- 使用Service Worker实现三级缓存:
效果对比:
| 指标 | 优化前 | 优化后 | 提升幅度 |
|————–|————–|————–|———-|
| 首屏加载时间 | 3.2s | 0.8s | 75% |
| 图片重载率 | 62% | 9% | 85% |
| 离线可用率 | 0% | 92% | |
常见问题与解决方案
Q1:缓存图片导致页面无法获取最新内容?
解决方案:
- 为缓存资源添加版本参数:
logo.png?v=1.0.1
- 使用Service Worker的
updatefound
事件通知用户刷新:self.addEventListener('updatefound', event => { clients.claim().then(() => { clients.matchAll({type: 'window'}).forEach(client => { client.navigate(client.url); // 强制刷新页面 }); }); });
- 配置服务器返回强缓存失效头部:
Cache-Control: no-cache
Q2:如何判断图片是否已缓存?
检测方法:
async function checkCache(url) { try { const cache = await caches.open('image-cache-v1'); const match = await cache.match(url); return match ? '已缓存' : '未缓存'; } catch(e) { return '检测失败'; } }