配了三年 PWA,每次用户离线提交表单都石沉大海——今天 Background Sync 把这件事从根上原生化了

每次用户填完表单点了提交,结果网络抖了一下,表单就这么消失了——这种体验做了三年 PWA 的人应该不陌生。今天 Background Sync API 把这件事从根上原生化了:用户提交时如果没网,浏览器会帮你把请求排队,等网络恢复后自动重试,整个过程不需要任何第三方库。

三种 API,用对场景才不踩坑

Background Sync 不是只有一个 API,而是三个各司其职的组合:

Background Sync(一次性):最常用。注册一个 tag,网络恢复时浏览器自动触发 service worker 的 sync 事件,重试失败请求。适合表单提交、消息发送、状态更新。Chrome 49+ 就支持了,但 Safari 至今不支持,Firefox 在考虑中。

Periodic Background Sync(周期性):让浏览器按它觉得合适的间隔唤醒 service worker 去抓新内容。注意:间隔不是你想设多少就多少,浏览器会根据电量、用户 engagement 指数、是否是已知网络来综合决定,开发者只能设一个最小间隔。还需要 PWA 已安装 + 用户明确授权。

Background Fetch(大文件):下载播客、视频、大型文件时,即使 tab 关了也继续下载。有进度事件,有 UI 进度条,浏览器接管整个生命周期。适合内容平台、在线教育。

核心代码:三行搞定离线表单重试

先注册 sync:

// 页面端:网络挂了就把请求排队
async function submitForm(data) {
  try {
    await fetch('/api/submit', {
      method: 'POST',
      body: JSON.stringify(data)
    });
  } catch {
    // 网络失败,注册后台同步
    const reg = await navigator.serviceWorker.ready;
    await reg.sync.register('form-submit');
  }
}

service worker 监听 sync 事件:

// service worker:网络恢复后自动触发
self.addEventListener('sync', event => {
  if (event.tag === 'form-submit') {
    event.waitUntil(resendFormData());
  }
});

就这么简单。失败后自动重试,指数退避由浏览器托管,不用自己写 setTimeout 循环。

三个坑,踩过才知道疼

坑一:Safari 永远不支持 Background Sync。这是硬伤,做 PWA 要有兜底方案:fallback 到 IndexedDB 队列 + 页面加载时检查。可以用 Workbox 的 BackgroundSyncPlugin 自动降级。

坑二:Periodic Background Sync 的间隔不受你控制。很多团队想用它做「每小时刷新一次数据」,结果发现实际间隔可能是 6 小时甚至更长。如果需要精确调度,还是得靠 server-side cron。

坑三:sync 事件执行时间有限制。service worker 被唤醒后只有几秒的执行窗口,大文件同步别走这个 API,用 Background Fetch。

三步下一步

第一步,打开 Chrome DevTools → Application → Service Workers,把 Periodic Background Sync 和 Background Sync 的调试面板摸熟,这是理解行为最直接的方式。

第二步,找一个你现有的表单场景,加上 Background Sync 队列,用 Lighthouse 的 PWA checklist 验证行为是否如预期。

第三步,如果你的 PWA 有内容刷新需求,评估 Periodic Background Sync 是否满足需求——如果精度要求高,考虑 server-side 方案作为补充。

关键就一句:用户填完表单点了提交,结果网络抖了一下表单就消失了——这件事今天有浏览器原生解法了。

评论区

0 条评论

登录后可评论。

阿速·性能优化 15 阅读