background sync 仅在https、service worker active且浏览器支持(chrome/edge等)时触发,需先存数据到indexeddb再注册,sw中须用event.waituntil包裹并确保幂等。

Background Sync 不是“注册就执行”,它只在网络恢复且 Service Worker 处于 active 状态时才可能触发 sync 事件;不满足条件时,registration.sync.register('tag') 会静默失败或抛错,根本不会进 self.addEventListener('sync', ...)。
为什么调用 registration.sync.register() 后没反应
最常见的不是代码写错,而是环境卡在三个硬性门槛上:
-
SyncManager仅在 Chrome、Edge 和部分 Android WebView 中可用;Firefox 和 Safari 完全不支持 —— 别在这两个浏览器里调试 - 必须运行在 HTTPS(或
localhost),HTTP 页面即使调用成功,也会被浏览器直接忽略 - 必须等
navigator.serviceWorker.readyresolve 后再注册;刚register('/sw.js')就立刻调reg.sync.register(),大概率报InvalidStateError - 浏览器可能因内存压力、标签页关闭或后台节流,终止 Service Worker 并丢弃已注册的 tag —— 可用
registration.sync.getTags()检查是否还在
如何在主线程安全注册同步任务
用户点击提交按钮时,不能只调 reg.sync.register('submit-form') 就完事。数据必须先落盘,否则页面刷新或崩溃就丢了:
- 先用
indexedDB存下表单内容(不能用localStorage,SW 里访问不到) - 再调
reg.sync.register('submit-form'),并用try/catch包裹,捕获NotSupportedError或InvalidStateError - 注册后立即调
reg.sync.getTags()验证是否写入成功(返回Promise<string></string>) - 不要重复注册同名 tag:多次调用不会覆盖,但可能触发多次 sync,需在 SW 端做幂等判断
示例(主线程):
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
if ('serviceWorker' in navigator && 'SyncManager' in window) {
navigator.serviceWorker.ready.then(reg => {
// 先存数据
saveToIDB('pending-submissions', { id: Date.now(), data: formData });
// 再注册同步
try {
reg.sync.register('submit-form');
} catch (err) {
console.error('Sync register failed:', err);
}
});
}
如何在 sw.js 中正确处理 sync 事件
这个回调里不能碰 DOM、不能读 localStorage、不能直接发请求而不包裹 event.waitUntil():
- 必须用
event.waitUntil(promise)包裹整个逻辑,否则浏览器可能在 promise resolve 前就终止 SW - 只能通过
indexedDB读取待同步数据 ——fetch()前务必确认数据存在 - 若
fetch()失败,可再次调registration.sync.register(tag)触发重试,但要加防抖或最大重试次数,避免指数退避拉得太长 - 弱网下避免并发太多请求,建议用
Promise.allSettled(chunks)分批发送,而不是Promise.all()
示例(sw.js):
self.addEventListener('sync', event => {
if (event.tag === 'submit-form') {
event.waitUntil(
readFromIDB('pending-submissions')
.then(dataList => {
if (!dataList.length) return;
return Promise.allSettled(
dataList.map(item =>
fetch('/api/submit', {
method: 'POST',
body: JSON.stringify(item),
headers: { 'Content-Type': 'application/json' }
})
)
);
})
.then(results => {
const successIds = results
.map((r, i) => (r.status === 'fulfilled' ? i : -1))
.filter(i => i !== -1);
return deleteFromIDB('pending-submissions', successIds);
})
.catch(err => console.error('Sync failed:', err))
);
}
});
容易被忽略的关键点
Background Sync 的触发时机由浏览器调度,你无法控制“什么时候执行”——它只保证“最终会执行一次”,且可能延迟数小时。如果你需要强时效性(比如 5 秒内必须发出去),它根本不适用;真正可靠的做法是:前端自己监听 online 事件 + 主动重发队列,把 Background Sync 当作最后一道兜底保险。另外,后端接口必须设计为幂等,因为浏览器重试机制不可控,同一 tag 可能被执行多次。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










