H5 Service Worker 离线缓存策略

举报
yd_229723446 发表于 2026/10/09 09:54:10 2026/10/09
【摘要】 H5 Service Worker 离线缓存策略Service Worker 可以拦截页面请求并使用缓存响应,为弱网和离线场景提供能力。但缓存策略设计不当会让用户长期看到旧页面、接口数据串号,甚至新旧脚本互不兼容。离线能力应按资源类型选择策略,并通过明确版本和更新流程管理生命周期。 一、理解独立生命周期Service Worker 与页面生命周期分开,主要经历安装、等待、激活和运行阶段。新...

H5 Service Worker 离线缓存策略

Service Worker 可以拦截页面请求并使用缓存响应,为弱网和离线场景提供能力。但缓存策略设计不当会让用户长期看到旧页面、接口数据串号,甚至新旧脚本互不兼容。离线能力应按资源类型选择策略,并通过明确版本和更新流程管理生命周期。

一、理解独立生命周期

Service Worker 与页面生命周期分开,主要经历安装、等待、激活和运行阶段。新版本下载完成后,可能要等旧页面关闭才激活。

因此,发布新版本不能假设所有页面立即由新逻辑控制。页面协议、缓存结构和消息格式需要考虑新旧版本短暂共存。

二、只缓存明确允许的内容

资源可以分为:

  • 应用外壳:基础脚本、样式和固定图标。
  • 页面内容:文章、商品列表等可更新数据。
  • 用户数据:账户与个性化信息。
  • 实时或敏感数据:不能使用过期结果的内容。

应用外壳适合版本化缓存;用户和关键业务数据必须按账户、有效期和安全要求处理,不能默认加入公共缓存。

三、为缓存设置版本

const CACHE_PREFIX = 'offline-demo-';
const SHELL_CACHE = `${CACHE_PREFIX}shell-v4`;
const CONTENT_CACHE = `${CACHE_PREFIX}content-v2`;
const ACTIVE_CACHES = new Set([SHELL_CACHE, CONTENT_CACHE]);

self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(names => Promise.all(
      names
        .filter(name => (
          name.startsWith(CACHE_PREFIX) && !ACTIVE_CACHES.has(name)
        ))
        .map(name => caches.delete(name))
    ))
  );
});

删除范围必须限于当前应用管理的缓存命名空间。真实项目如果还有其他功能缓存,应一起纳入版本清单,不能清空全部缓存。

四、缓存优先适合稳定资源

async function cacheFirst(request) {
  const cache = await caches.open(SHELL_CACHE);
  const cached = await cache.match(request);
  if (cached) return cached;

  const response = await fetch(request);
  if (response.ok) {
    await cache.put(request, response.clone());
  }
  return response;
}

带内容摘要的构建资源适合缓存优先,因为内容变化时资源标识也变化。没有版本标识的页面文档如果长期缓存优先,可能无法及时获得新入口。

五、网络优先适合更新内容

async function networkFirst(request, cacheName) {
  const cache = await caches.open(cacheName);
  try {
    const response = await fetch(request);
    if (response.ok) {
      await cache.put(request, response.clone());
    }
    return response;
  } catch (error) {
    const cached = await cache.match(request);
    if (cached) return cached;
    throw error;
  }
}

只有业务允许展示旧数据时,失败后才返回缓存。交易状态、余额等关键内容不能为了“有结果”而使用过期响应。

六、按请求类型路由策略

self.addEventListener('fetch', event => {
  const request = event.request;
  if (request.method !== 'GET') return;

  if (isVersionedAsset(request)) {
    event.respondWith(cacheFirst(request));
    return;
  }

  if (isCacheableContent(request)) {
    event.respondWith(networkFirst(request, CONTENT_CACHE));
  }
});

分类函数应基于项目统一请求描述或确定规则。写操作不应直接缓存,也不能在离线时假装提交成功。

七、离线写入需要独立队列

如果产品允许离线编辑,应先把业务内容和待同步操作持久化,再由明确同步任务重放。队列需要稳定操作标识、顺序和冲突规则。

Service Worker 只能提供执行机会,不能代替幂等协议。支付、下单等非幂等操作不应无条件后台重放。

八、更新提示不要强制打断

新 Worker 准备好后,页面可以提示用户在合适时机刷新。强制立即接管可能让当前表单和旧脚本状态不兼容。

确需立即更新的安全修复,也要先保存允许恢复的草稿,并清楚告知用户。是否跳过等待应由发布策略决定,不是所有版本的默认选项。

九、控制缓存容量与清理

浏览器存储空间有限,缓存可能被系统清理。离线页面不能把缓存当作永久唯一数据源。

内容缓存应设置数量或时间边界,账户退出后精确清理个人数据。清理逻辑不能只在安装阶段执行,因为用户可能长期不更新版本。

十、测试离线矩阵

至少验证:

  • 首次访问时完全离线。
  • 已缓存后离线刷新。
  • 新旧 Worker 同时存在。
  • 新资源发布后能否正确更新。
  • 缓存内容过期和容量淘汰。
  • 用户切换账户后数据不串用。
  • 写操作离线时显示真实状态。
  • 缓存缺失时错误页面可理解。

总结

Service Worker 离线能力依赖清晰的资源分类。版本化外壳使用缓存优先,允许旧数据的内容采用网络优先,敏感与实时数据遵循更严格策略。再配合缓存清理、平滑更新和幂等离线队列,才能避免“离线可用”变成“长期陈旧”。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。