通知 · 概念
用于内容更新的周期性后台同步
发布于 更新于
周期性后台同步让已安装的 PWA 按浏览器选择的节奏刷新缓存内容:在没有页面打开时,于 Service Worker 内触发 periodicsync 事件。它存在的目的是让新闻或天气应用打开时显示最新数据而不是加载圈。它仅限 Chromium,并以安装和用户实际打开应用的频率为闸门。
页面用 registration.periodicSync.register(tag, { minInterval }) 注册一个 tag;随后浏览器在设备在线时以不高于 minInterval 的频率在 Service Worker 内触发 periodicsync,且只在它认为应用值得唤醒的期间持续。该 API 表面(PeriodicSyncManager、register()、getTags()、unregister()、periodicsync 事件)存在于 Chrome 80 和 Edge 80,其他地方都没有(BCD api.PeriodicSyncManager);方法级参考见 Service Worker 条目。
Chrome 的闸门
Section titled “Chrome 的闸门”Chrome 只为用户已安装并以独立应用方式启动过的 Web App 触发该事件,不为标签页中的站点触发,并且只在设备连接到此前用过的网络时触发(Periodic background sync,developer.chrome.com)。频率与 Chrome 为每个源维护的站点参与度得分挂钩,可在 about://site-engagement/ 查看:得分为零意味着完全没有事件,得分越高允许的同步越接近 minInterval。用户不再打开应用,得分衰减,事件随之停止。因此 minInterval 是下限而不是时间表,minInterval: 0 的注册把节奏完全交给 Chrome。
该特性由 periodic-background-sync 权限把关,Chrome 对已安装应用自动授予且不弹提示。navigator.permissions.query({ name: 'periodic-background-sync' }) 在窗口或 Service Worker 中都报告 granted 或 denied;register() 在权限被拒时以 NotAllowedError 拒绝,注册没有活跃 worker 时以 InvalidStateError 拒绝,从非顶级浏览上下文的窗口调用时以 InvalidAccessError 拒绝(PeriodicSyncManager: register(),developer.mozilla.org)。
适合什么,不适合什么
Section titled “适合什么,不适合什么”后台同步(Background Sync)虽然名字相近,但做的是在网络恢复后重试失败的请求;周期性后台同步是按节奏拉取新数据。Web Push 也能唤醒 worker,但会用通知打断用户,而且必须在 userVisibleOnly 之下这样做。周期性同步是唯一安静且重复的选项,这让它适合每日文章缓存,而不适合任何必须在特定时刻发生的事情;后者没有已发布的 API,通知触发器条目解释了原因。
两个示例都保留页面加载时的刷新作为兜底,并让 API 在可用的地方替代它。
在应用具备条件时注册每日文章刷新
Section titled “在应用具备条件时注册每日文章刷新”在 Service Worker 活跃且权限已授予之后注册。catch 覆盖 Chrome 的标签页场景和所有其他引擎,代码退回到加载时刷新。
async function enableDailyRefresh() { const registration = await navigator.serviceWorker.ready; if (!('periodicSync' in registration)) { return refreshOnLoad(); // Firefox、Safari,或未安装的 Chrome 标签页 } const status = await navigator.permissions.query({ name: 'periodic-background-sync' }); if (status.state !== 'granted') return refreshOnLoad(); try { await registration.periodicSync.register('update-articles', { minInterval: 24 * 60 * 60 * 1000 }); } catch { refreshOnLoad(); // 权限被拒或没有活跃 worker:行为与以前一致 }}refreshOnLoad() 是原有行为,没有该 API 的引擎不会失去任何东西;API 只是在可用的地方去掉了加载圈。
处理事件并跳过加载时刷新
Section titled “处理事件并跳过加载时刷新”worker 在 event.waitUntil() 内缓存响应;页面检查 getTags(),同步已注册时跳过自己的刷新,因为缓存已经是新的。
// Service Workerself.addEventListener('periodicsync', (event) => { if (event.tag === 'update-articles') { event.waitUntil(caches.open('articles').then((cache) => cache.add('/api/articles'))); }});
// 页面async function maybeRefresh(registration) { const tags = 'periodicSync' in registration ? await registration.periodicSync.getTags() : []; if (!tags.includes('update-articles')) refreshOnLoad();}处理函数要小:Chrome 给 worker 的时间窗有限,一次在计费网络上下载数兆字节的同步正是会降低参与度预算的那种行为。
- Web Periodic Background Synchronization(wicg.github.io)
- Periodic background sync(developer.chrome.com)
- PeriodicSyncManager.register()
- 后台同步
- Web Push 与 PushManager.subscribe()
- 通知触发器(showTrigger)
规范
| 规范 | 状态 |
|---|---|
| Periodic Background Sync(周期性后台同步) | WICG 草案 |
- 图例
- 支持
- 部分支持
- 需开启标志
- 不支持
- 未知
| 浏览器 / 平台 | 支持 | 版本 | 置信度 | 来源 | 备注 |
|---|---|---|---|---|---|
| Chrome (Desktop) | 支持 | 80 | 高 | 来源 | — |
| Chrome (Android) | 支持 | 80 | 高 | 来源 | 1 |
| Edge (Desktop) | 支持 | 80 | 高 | 来源 | 2 |
| Firefox (Desktop) | 不支持 | — | 高 | 来源 | 3 |
| Firefox (Android) | 不支持 | — | 高 | 来源 | 45 |
| Safari (macOS) | 不支持 | — | 高 | 来源 | 6 |
| Safari (iOS) | 不支持 | — | 高 | 来源 | 78 |
| Samsung Internet | 支持 | 13.0 | 高 | 来源 | 9 |
| WebView (Android) | 不支持 | — | 高 | 来源 | 10 |
- 由 browser-compat-data 镜像自 Chrome 的数据推导。
- 由 browser-compat-data 镜像自 Chrome 的数据推导。
- browser-compat-data 未记录 Firefox 的支持。
- browser-compat-data 未记录 Firefox for Android 的支持。
- 由 browser-compat-data 镜像自 Firefox 的数据推导。
- browser-compat-data 未记录 Safari 的支持。
- browser-compat-data 未记录 iOS 版 Safari 的支持。
- 由 browser-compat-data 镜像自 Safari 的数据推导。
- 由 browser-compat-data 镜像自 Chrome Android 的数据推导。
- 实现跟踪:https://crbug.com/40151529。