HTML5 离线存储

HTML5 离线存储(通常指 Application Cache )是早期用于实现 Web 应用离线访问的技术,但由于其设计缺陷已被废弃 。现代 Web 开发中,取而代之的是更强大的 Service Worker + Cache API 方案(属于 Progressive Web Apps 技术栈)。下面详细解析两者:


一、已被废弃的 Application Cache (AppCache)

1. 基本原理
  • 通过一个 manifest 清单文件 (如 app.manifest)声明需要缓存的资源。
  • 浏览器根据清单下载资源并存储在离线缓存中。
2. 使用步骤
html 复制代码
<!-- 在 html 标签中声明 manifest 文件 -->
<html manifest="app.manifest">

app.manifest 文件示例

manifest 复制代码
CACHE MANIFEST
# v1.0.0  → 版本号(更新缓存需修改此号)

CACHE:    # 需要缓存的资源
/css/style.css
/js/app.js
/images/logo.png
/index.html

NETWORK:  # 必须在线访问的资源(白名单)
/api/
/login

FALLBACK: # 离线时替代方案
/offline.html     # 所有失败请求的兜底页面
/images/ /images/offline.png # 特定路径的替代
3. 主要问题(被废弃原因)
  • 更新机制不透明:必须修改 manifest 文件(如版本号)才能触发更新。
  • 白名单机制死板NETWORKFALLBACK 规则难以维护。
  • 缓存污染风险:一旦缓存失败,可能导致整个应用无法使用。
  • 无细粒度控制:无法编程式管理缓存。
  • 并发问题:多标签页同时更新可能冲突。

⚠️ 现代浏览器已移除支持(Chrome 70+、Firefox 46+ 等弃用)。


二、现代方案:Service Worker + Cache API

核心优势
  • 完全可编程:通过 JavaScript 精细控制缓存逻辑。
  • 后台运行:独立于主线程,不阻塞页面渲染。
  • 拦截网络请求:可自定义缓存策略(如网络优先/缓存优先)。
1. 实现步骤
(1) 注册 Service Worker
html 复制代码
<!-- 在页面中注册 -->
<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)
javascript 复制代码
// 定义缓存名称(版本更新时修改此名)
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. 常用缓存策略
javascript 复制代码
// 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
  • 更新机制
    1. 修改 Service Worker 文件(即使1字节变化)
    2. 新 SW 安装后处于 waiting 状态
    3. 通过 skipWaiting() 强制激活或关闭所有页面后生效

三、最佳实践

  1. 仅缓存必要资源:避免占用过多存储空间。
  2. 设置缓存过期:定期清理旧缓存。
  3. 提供离线回退:如返回离线页面或默认图片。
  4. 结合 IndexedDB:存储结构化数据(如用户设置)。
  5. 使用 Workbox:Google 官方库,简化 Service Worker 开发:
javascript 复制代码
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 应用)的核心技术之一。

相关推荐
加班是不可能的,除非双倍日工资2 小时前
css预编译器实现星空背景图
前端·css·vue3
wyiyiyi2 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
gnip3 小时前
vite和webpack打包结构控制
前端·javascript
excel3 小时前
在二维 Canvas 中模拟三角形绕 X、Y 轴旋转
前端
阿华的代码王国3 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
一条上岸小咸鱼3 小时前
Kotlin 基本数据类型(三):Booleans、Characters
android·前端·kotlin
Jimmy3 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
ZXT4 小时前
promise & async await总结
前端
Jerry说前后端4 小时前
RecyclerView 性能优化:从原理到实践的深度优化方案
android·前端·性能优化
画个太阳作晴天4 小时前
A12预装app
linux·服务器·前端