background-sync 仅提供网络恢复通知,不能单独实现自动重试;需配合 IndexedDB 持久化请求数据、幂等接口与用户反馈机制形成完整离线重试闭环。

不能靠 background-sync 单独实现“自动重试”,它只提供一个网络恢复后的执行信号。真正起作用的是你主动设计的缓存+重试逻辑,background-sync 只是那个“该干活了”的通知。
必须先持久化数据,不能依赖原始请求
fetch 事件中拦截到的 Request 对象无法跨事件保存——它是个不可序列化的流。断网时提交的表单、XML 或文件上传,必须立刻提取关键信息并存进 IndexedDB:
- 把 URL、method、headers(去掉二进制字段)和 body(JSON 字符串 / base64 / ArrayBuffer)单独存为一条记录
- 为每条记录生成唯一 ID 和时间戳,方便排序与去重
- 如果含文件,页面端需提前用 FileReader 转成 ArrayBuffer 再存,Service Worker 里重建 Blob
- 避免在 Service Worker 中解析 XML 或 DOM,所有序列化工作必须在主线程完成
注册 sync 任务要守规矩
注册不是随时都能做,浏览器有明确限制:
- 只能在用户交互(如点击按钮、submit 表单)后调用 registration.sync.register('tag')
- 必须确保 Service Worker 已激活且页面同源;HTTPS 是硬性要求(localhost 除外)
- 要用 try/catch 包裹注册逻辑,捕获 NotSupportedError(Firefox/Safari 不支持)或 InvalidStateError(SW 未就绪)
- 不要重复注册同名 tag:多次调用不会覆盖,但可能触发多次 sync,需在 SW 端做幂等判断
sync 事件里要做完整闭环
收到 sync 事件不等于任务完成,你得自己读库、发请求、处理结果、清理或重试:
- 用 event.waitUntil() 包裹整个异步流程,否则 SW 可能被系统终止
- 先查 IndexedDB 是否还有待发记录;没有就直接 return
- 逐条 fetch,成功则删除该条;失败则记录错误、保留原记录,并可选加退避后重新注册同名 tag
- 服务端接口必须支持幂等(例如用客户端生成的 request-id 做去重),否则重试会引发重复操作
别忘了给用户真实反馈
后台同步对用户是隐形的,但体验不能是黑盒:
- 表单提交后立即显示“已加入离线队列”,而不是“提交成功”
- 用 postMessage 把重试结果(成功/失败/跳过)同步回页面,更新 UI 状态
- 页面加载时可主动询问 Service Worker 当前待同步数量,用小红点或横幅提醒用户
- 对关键操作(如下单),失败后建议提供手动重试入口,别只靠后台默默循环

















