HTML5 離線存儲(通常指 Application Cache)是早期用于實現 Web 應用離線訪問的技術,但由于其設計缺陷已被廢棄。現代 Web 開發中,取而代之的是更強大的 Service Worker + Cache API 方案(屬于 Progressive Web Apps 技術棧)。下面詳細解析兩者:
一、已被廢棄的 Application Cache (AppCache)
1. 基本原理
- 通過一個
manifest
清單文件(如app.manifest
)聲明需要緩存的資源。 - 瀏覽器根據清單下載資源并存儲在離線緩存中。
2. 使用步驟
<!-- 在 html 標簽中聲明 manifest 文件 -->
<html manifest="app.manifest">
app.manifest
文件示例:
CACHE MANIFEST
# v1.0.0 → 版本號(更新緩存需修改此號)CACHE: # 需要緩存的資源
/css/style.css
/js/app.js
/images/logo.png
/index.htmlNETWORK: # 必須在線訪問的資源(白名單)
/api/
/loginFALLBACK: # 離線時替代方案
/offline.html # 所有失敗請求的兜底頁面
/images/ /images/offline.png # 特定路徑的替代
3. 主要問題(被廢棄原因)
- 更新機制不透明:必須修改 manifest 文件(如版本號)才能觸發更新。
- 白名單機制死板:
NETWORK
和FALLBACK
規則難以維護。 - 緩存污染風險:一旦緩存失敗,可能導致整個應用無法使用。
- 無細粒度控制:無法編程式管理緩存。
- 并發問題:多標簽頁同時更新可能沖突。
?? 現代瀏覽器已移除支持(Chrome 70+、Firefox 46+ 等棄用)。
二、現代方案:Service Worker + Cache API
核心優勢
- 完全可編程:通過 JavaScript 精細控制緩存邏輯。
- 后臺運行:獨立于主線程,不阻塞頁面渲染。
- 攔截網絡請求:可自定義緩存策略(如網絡優先/緩存優先)。
1. 實現步驟
(1) 注冊 Service Worker
<!-- 在頁面中注冊 -->
<script>
if ('serviceWorker' in navigator) {navigator.serviceWorker.register('/sw.js').then(reg => console.log('SW 注冊成功')).catch(err => console.error('SW 注冊失敗', err));
}
</script>
(2) 編寫 Service Worker 腳本 (sw.js
)
// 定義緩存名稱(版本更新時修改此名)
const CACHE_NAME = 'my-app-v1';// 需要預緩存的資源
const PRE_CACHE = ['/','/index.html','/css/main.css','/js/app.js','/images/hero.jpg'
];// 安裝階段:預緩存關鍵資源
self.addEventListener('install', event => {event.waitUntil(caches.open(CACHE_NAME).then(cache => cache.addAll(PRE_CACHE)));
});// 激活階段:清理舊緩存
self.addEventListener('activate', event => {event.waitUntil(caches.keys().then(cacheNames => {return Promise.all(cacheNames.map(name => {if (name !== CACHE_NAME) return caches.delete(name);}));}));
});// 攔截請求:自定義緩存策略
self.addEventListener('fetch', event => {event.respondWith(// 策略1:緩存優先(適用于靜態資源)caches.match(event.request).then(cachedResponse => {if (cachedResponse) return cachedResponse;// 策略2:網絡請求并緩存(適用于動態內容)return fetch(event.request).then(response => {// 只緩存成功響應if (!response || response.status !== 200) return response;const responseToCache = response.clone();caches.open(CACHE_NAME).then(cache => cache.put(event.request, responseToCache));return response;});}));
});
2. 關鍵特性
功能 | 實現方式 |
---|---|
預緩存 | install 事件中使用 cache.addAll() |
動態緩存 | fetch 事件中通過 cache.put() 緩存網絡響應 |
緩存策略 | 可自由實現:緩存優先/網絡優先/增量更新等 |
緩存清理 | activate 事件中刪除舊緩存 |
離線回退 | 在 fetch 事件中返回兜底內容(如離線頁面) |
3. 常用緩存策略
// 1. 緩存優先(適合靜態資源)
caches.match(request).then(cached => cached || fetch(request))// 2. 網絡優先(適合頻繁更新數據)
fetch(request).catch(() => caches.match(request))// 3. 增量更新(先返回緩存,再更新緩存)
event.respondWith(caches.match(request));
event.waitUntil(fetch(request).then(response => cache.put(request, response))
);
4. 調試與更新
- 調試:Chrome DevTools → Application → Service Workers
- 更新機制:
- 修改 Service Worker 文件(即使1字節變化)
- 新 SW 安裝后處于
waiting
狀態 - 通過
skipWaiting()
強制激活或關閉所有頁面后生效
三、最佳實踐
- 僅緩存必要資源:避免占用過多存儲空間。
- 設置緩存過期:定期清理舊緩存。
- 提供離線回退:如返回離線頁面或默認圖片。
- 結合 IndexedDB:存儲結構化數據(如用戶設置)。
- 使用 Workbox:Google 官方庫,簡化 Service Worker 開發:
import {precacheAndRoute} from 'workbox-precaching';
precacheAndRoute([...]); // 自動生成緩存清單
四、瀏覽器兼容性
- Service Worker:Chrome 40+、Firefox 44+、Edge 17+、Safari 11.1+
- Cache API:同 Service Worker 支持范圍
- 安全要求:必須使用 HTTPS(本地開發允許
localhost
)
總結對比
特性 | Application Cache (廢棄) | Service Worker + Cache API |
---|---|---|
控制粒度 | 聲明式(manifest文件) | 編程式(JavaScript) |
更新機制 | 手動修改 manifest | 文件內容變化自動更新 |
請求攔截 | ? 不支持 | ? 完全控制網絡請求 |
后臺同步 | ? 不支持 | ? 支持后臺同步(Background Sync) |
緩存策略靈活性 | 極低 | 極高(可自定義邏輯) |
現代瀏覽器支持 | 已廢棄 | 廣泛支持 |
💡 現代 Web 離線存儲應優先使用 Service Worker,它提供了更強大、靈活的離線能力,是 PWA(漸進式 Web 應用)的核心技術之一。