跳转到内容

Background sync:重连后重试失败的请求

发布于 更新于

一句话: Background sync(后台同步)让 web 应用的 service worker 推迟某个动作——例如发送一条 排队中的消息——直到浏览器判断设备重新获得网络连接,而不是在网络不可用时直接让它失败。

Background sync 流程图:请求在离线时失败,页面把它存入 IndexedDB 并调用 sync.register('outbox');浏览器保留该 tag 直到网络恢复,然后在 service worker 中触发 sync 事件,worker 在 event.waitUntil() 内重放队列;Promise 兑现则清除注册,lastChance 为 false 的拒绝会稍后按退避重试,lastChance 为 true 的拒绝则不再重试。
Background sync:排队、注册、在 sync 事件中重放,以及 Promise 落定的三种结果。

当某次 fetch 因设备离线而失败时,页面可以注册一个同步请求,而不是直接放弃。浏览器会保留这个注册, 一旦它判断设备已恢复连接,就会在 service worker 中触发 sync 事件,让应用重试这项被推迟的工作—— 即便最初注册它的页面早已关闭。

该 API 通过 ServiceWorkerRegistration.sync 访问,它返回一个 SyncManager:

async function queueMessage() {
try {
await sendMessage();
} catch {
const registration = await navigator.serviceWorker.ready;
if ('sync' in registration) {
await registration.sync.register('send-queued-message');
}
}
}
  • SyncManager.register(tag) 使用给定的 tag 注册一个一次性同步请求,返回的 Promise 在注册 完成后 resolve。
  • SyncManager.getTags() resolve 为当前已注册的 tag 列表。

在 service worker 中,应用监听 sync 事件,并把重试工作的 Promise 传给 waitUntil(), 将事件的生命周期延长。用户代理仍可对这段延长的时间施加自己的执行与生命周期限制,因此 waitUntil() 并不保证工作一定完成——参见下方“常见问题”:

self.addEventListener('sync', (event) => {
if (event.tag === 'send-queued-message') {
event.waitUntil(sendQueuedMessage());
}
});

Background sync 是 Chromium(Blink)的特性——Chrome、Edge 和三星 Internet 都已实现,而 WebKit (Safari)和 Gecko(Firefox)尚未实现。

  • 图例
  • 支持
  • 部分支持
  • 需开启标志
  • 不支持
  • 未知
浏览器 / 平台支持版本置信度来源备注
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 · 全球使用占比: 72 % (StatCounter 2026-05)

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

更多细节见兼容性页面。

  • 根据规范,当注册它的页面或 worker 仍在运行时,事件会在连接恢复可用后触发——但不一定是立即 触发。如果该上下文已不再运行,用户代理则只被期望在其“最方便的时机”触发该事件,而不是按任何 有保证的时间表。
  • 规范允许用户代理对 SyncEvent 施加自己的执行时长与生命周期限制——调用 event.waitUntil() 并不 保证浏览器会让任意长的工作在终止 worker 之前完成。
  • 截至目前,Background sync 在 WebKit(Safari)和 Gecko(Firefox)中不受支持——始终把这种重试 设计为一种增强,而不是成功的唯一路径。
  • 根据规范,失败的事件可能会依据用户代理自定的启发式规则重试,除非它是最后一次机会——此时不再 重试。重试并不保证最终一定成功,这也不是一个周期性的计划任务。

在注册 tag 之前先检测 SyncManager,并在它不可用时回退为立即重试(或在下次加载页面时重试):

function supportsBackgroundSync(registration) {
return 'sync' in registration;
}
async function deferOrRetry(registration, tag, retryNow) {
if (!supportsBackgroundSync(registration)) {
return retryNow(); // 没有 Background Sync:改为立即重试
}
return registration.sync.register(tag);
}