Background Sync 不是注册即触发,必须满足网络在线、Service Worker 持续激活、同步任务未被浏览器丢弃三条件;否则 sync 事件不会触发,常见于非 Chrome/Edge 浏览器、HTTP 环境或未等 ready 就注册。
Background Sync 不是“注册了就能自动跑”,它必须满足网络在线 + Service Worker 持续激活 + 同步任务未被浏览器丢弃这三个条件,否则 sync 事件根本不会触发。
registration.sync.register('my-tag') 后没反应?这是最常遇到的卡点。表面上注册成功,但控制台看不到 sync 事件日志,原因往往不是代码写错,而是环境不达标:
SyncManager 只在 Chrome、Edge 和部分 Android WebView 中可用,Firefox 和 Safari 完全不支持 —— 别在这些浏览器里调试localhost)下运行,HTTP 页面即使注册了也会静默失败active 状态,且不能刚注册完就立刻调用 register();要等 navigator.serviceWorker.ready Promise resolve 后再操作getTags() 返回空数组)self.addEventListener('sync', ...) 里能做什么?这个回调是唯一能安全执行网络请求的离线时机,但它有硬性限制:
window、document 或任何 DOM API —— Service Worker 是无窗口环境event.waitUntil() 包裹异步逻辑,否则浏览器可能在任务完成前就终止 WorkerIndexedDB 存取待同步数据(比如表单提交内容)fetch() 失败或 Promise reject,浏览器会按指数退避策略重试(最长可能等数小时),直到成功或标记 lastChance: true
典型写法示例:
立即学习“前端免费学习笔记(深入)”;
self.addEventListener('sync', event => { if (event.tag === 'form-submit') { event.waitUntil( // 从 IndexedDB 读出离线表单数据 readFromIDB('pending-submissions') .then(dataList => Promise.all( dataList.map(item => fetch('/api/submit', { method: 'POST', body: JSON.stringify(item), headers: { 'Content-Type': 'application/json' } })) )) .then(() => deleteFromIDB('pending-submissions')) .catch(err => console.error('Sync failed:', err)) ); }});
用户点击提交时,你不能只调用 register() 就完事。得先持久化数据,再注册同步任务,否则页面刷新或崩溃会导致数据丢失:
submit 事件,阻止默认提交行为indexedDB.open() 打开数据库,把表单字段存入 object store(如 pending-submissions)registration.sync.register('form-submit')
id 字段,并在同步成功后用该 id 删除记录注意:不要在 sync 回调里重新构造表单 DOM 或触发 UI 更新 —— 那些逻辑应该放在主页面监听 message 事件,由 Service Worker 主动 postMessage 通知。
靠 console.log 很难判断,得用工具链定位真实状态:
navigator.serviceWorker.ready.then(r => r.sync.getTags()),看返回数组是否包含你注册的 tagsync 事件fetch 请求发出真正容易被忽略的是:Background Sync 的重试机制完全不可控 —— 你无法指定重试次数、间隔或超时时间,只能依赖浏览器策略。如果业务对同步时效性敏感(比如支付确认),得额外加轮询兜底或改用 WebSocket/SSE 实时通道。