跳转到内容

Service Worker 中的概念

后台同步、周期同步与 Web Locks

发布于

有限可用不支持的浏览器: Firefox (Desktop)、Firefox (Android)、Safari (macOS)、Safari (iOS)WICG 草案

Background Sync(后台同步)让 Service Worker 在用户代理判断网络条件合适时重试延后执行的工作。Periodic Background Sync(周期性后台同步)由浏览器选择时间唤醒 Service Worker 更新数据;Web Locks 则协调仍在运行的标签页与 worker,避免它们同时操作同一个应用资源。

回退方案取决于支持范围。BCD api.SyncManager 记录 Chrome 49 起支持后台同步,Edge 镜像该支持,Firefox 和 Safari 未记录支持;api.PeriodicSyncManager 记录 Chrome 80 起支持周期性后台同步,Edge 镜像该支持,Firefox 和 Safari 未记录支持;api.LockManager 记录 Chrome 69 起支持 Web Locks,Edge 镜像该支持,并记录 Firefox 96 和 Safari 15.4 起支持。

这三套机制处理的调度问题并不相同。后台同步通过 ServiceWorkerRegistration.sync 注册标签,用户代理随后向活动 Service Worker 派发 sync 事件。周期性后台同步通过 ServiceWorkerRegistration.periodicSync 注册标签和 minInterval,规范把实际触发时间交给用户代理决定。Web Locks 调用 navigator.locks.request();同名锁可用后,浏览器运行回调,回调返回的 Promise 结束时释放锁。

机制 触发条件 执行环境 可用的回退方案
Background Sync 调用 sync.register() 后,用户代理判断网络条件合适 Service Worker 的 sync 事件 下次页面打开时重试
Periodic Background Sync 用户代理选择时间,频率不会高于 minInterval 所表达的下限 Service Worker 的 periodicsync 事件 页面打开时刷新
Web Locks 调用 navigator.locks.request() 后,同名锁变为可用 发起请求的窗口或 worker 不做跨上下文协调,或使用应用自己的租约

后台同步适合处理已经失败或主动延后的操作,例如发送已排队的表单。Background Sync 规范通过 SyncManager 定义一次性注册;另一份 Periodic Background Sync 规范通过 PeriodicSyncManager 定义周期性注册。注册不会替你持久保存请求;应先把请求数据写入存储,再注册标签,Service Worker 完成操作后再删除数据。

周期性后台同步适合更新没有用户动作也会过期的数据。Chrome 的说明指出,开发者无法控制具体同步时间;浏览器还会考虑用户参与度、以前使用过的网络、电量和连接状态。因此,minInterval 是最小间隔,不是定时器。

Web Locks 不会安排 Service Worker,也不等待网络恢复。Web Locks 规范规定同名独占锁逐个授予,同名共享锁可以同时授予多个请求。回调决定持锁时间,所以应只包住不能重叠的异步操作。页面关闭后,Web Lock 不能替代持久化的重试队列。

需求 选择 原因
网络恢复后重试已保存的写操作 Background Sync sync 事件面向延后执行的一次性工作
没有打开页面时更新缓存内容 Periodic Background Sync periodicsync 事件面向浏览器安排的周期刷新
阻止两个活动上下文同时更新同一条记录 Web Locks 同名独占锁会串行执行对应回调
在 Firefox 和 Safari 中使用同一套协调机制 Web Locks 这两个引擎记录了 LockManager 支持,没有记录两种 SyncManager 支持
要求精确的墙上时钟截止时间 均不适用 同步规范把派发时间交给用户代理,锁只管理争用

先保存需要持久化的工作,再单独处理运行时协调。下面两个示例都保留页面加载路径,让没有同步 API 的浏览器也能继续完成工作。

页面先把操作写入 IndexedDB,再请求一次性后台同步。如果没有 SyncManager,或者注册失败,只要页面仍开着,就直接调用同一个队列处理函数。

async function queueMessage(message) {
await outbox.put(message);
const registration = await navigator.serviceWorker.ready;
if (!('sync' in registration)) {
return flushOutbox();
}
try {
await registration.sync.register('send-outbox');
} catch (error) {
await flushOutbox();
reportRetryFallback(error);
}
}

Service Worker 处理同一份持久队列。把 Promise 交给 waitUntil(),用户代理就能按 Background Sync 事件模型,在 flushOutbox() 运行时延长事件生命周期。

self.addEventListener('sync', (event) => {
if (event.tag !== 'send-outbox') return;
event.waitUntil(flushOutbox());
});
self.addEventListener('message', (event) => {
if (event.data?.type !== 'flush-outbox') return;
event.waitUntil(flushOutbox());
});

页面仅在 API 和权限检查通过后注册周期刷新。失败分支立即刷新一次,后续重试交给下一次页面加载。

async function scheduleCatalogRefresh() {
const registration = await navigator.serviceWorker.ready;
if (!('periodicSync' in registration)) {
return refreshCatalogNow();
}
const status = await navigator.permissions.query({
name: 'periodic-background-sync',
});
if (status.state !== 'granted') return refreshCatalogNow();
try {
await registration.periodicSync.register('catalog', {
minInterval: 24 * 60 * 60 * 1000,
});
} catch (error) {
await refreshCatalogNow();
reportRefreshFallback(error);
}
}

若多个活动上下文都可能调用 refreshCatalogNow(),可用 Web Lock 包住它。这样只能消除活动上下文之间的重叠,不会替代持久队列,也不会产生 Service Worker 事件。

async function refreshCatalogOnce() {
if (!('locks' in navigator)) return refreshCatalogNow();
return navigator.locks.request('catalog-refresh', {
ifAvailable: true,
}, async (lock) => {
if (!lock) return { status: 'already-running' };
await refreshCatalogNow();
return { status: 'refreshed' };
});
}

后台同步兼容性数据和 Web Locks 兼容性数据说明了为何两处特性检测都不能省略。

规范

规范状态
Background Sync(后台同步)WICG 草案
  • 图例
  • 支持
  • 部分支持
  • 需开启标志
  • 不支持
  • 未知
浏览器 / 平台支持版本置信度来源备注
Chrome (Desktop)#支持49高来源—
Chrome (Android)#支持49高来源1
Edge (Desktop)#支持79高来源2
Firefox (Desktop)#不支持—高来源3
Firefox (Android)#不支持—高来源45
Safari (macOS)#不支持—高来源6
Safari (iOS)#不支持—高来源78
Samsung Internet#支持5.0高来源9
WebView (Android)#不支持—高来源10
  1. 由 browser-compat-data 镜像自 Chrome 的数据推导。
  2. 由 browser-compat-data 镜像自 Chrome 的数据推导。
  3. browser-compat-data 未记录 Firefox 的支持。
  4. browser-compat-data 未记录 Firefox for Android 的支持。
  5. 由 browser-compat-data 镜像自 Firefox 的数据推导。
  6. 实现跟踪:https://webkit.org/b/182565。
  7. 实现跟踪:https://webkit.org/b/182565。
  8. 由 browser-compat-data 镜像自 Safari 的数据推导。
  9. 由 browser-compat-data 镜像自 Chrome Android 的数据推导。
  10. 实现跟踪:https://crbug.com/40449796。

源数据: /compatibility/background-sync.json · 全球使用占比: 75 % (StatCounter 2026-09, CC BY-SA 4.0)

来源: 规范 · MDN · 最近核验 2026-10-03 · 置信度: 高 (由来源计算)