1. 介绍
本节为非规范性内容。
Web 应用经常在网络不可靠(例如移动电话)且生命周期未知(浏览器可能被终止或用户可能导航离开)的环境中运行。 这使得 Web 应用难以将其内容和状态与服务器保持同步。
此 API 的目的是缩短内容创建与服务器与 Web 应用之间内容同步的时间。它通过允许 Web 应用注册一个定期同步状态和数据的意图,并指定希望的最小间隔来实现。通过 service worker 事件,用户代理随后定期允许 Web 应用下载网络资源并更新状态。
由于此 API 依赖于 service workers,因此此 API 提供的功能仅在安全上下文中可用。
1.1. 示例
从浏览上下文注册最小间隔为一天的定期后台同步:async function registerPeriodicNewsCheck() { const registration= await navigator. serviceWorker. ready; try { await registration. periodicSync. register( 'fetch-news' , { minInterval: 24 * 60 * 60 * 1000 , }); } catch { console. log( 'Periodic Sync could not be registered!' ); } }
在 periodicsync 事件 在 service worker 中触发时的响应示例:
self. addEventListener( 'periodicsync' , event=> { event. waitUntil( fetchAndCacheLatestNews()); });
在上面的示例中 fetchAndCacheLatestNews 是一个开发者定义的函数是一个
开发者定义的函数,它从服务器获取最新的新闻文章并将它们本地存储,例如使用 Cache
API,以便离线使用。
2. 概念
当为 periodicsync 事件
对某个 周期性同步注册 registration 触发时,如果不存在其关联的 service worker 客户端,且这些客户端的 frame type 为 "top-level",
"auxiliary" 或 "nested",则该事件被视为在 后台运行,这些客户端是针对与 registration 关联的 origin 的 service worker registration
存在的情况除外。
3. 对 service worker 注册的扩展
A service worker registration additionally has:-
周期性同步处理队列,最初是 启动一个新的并行队列 的结果。
4. 构造
4.1. 周期性同步注册
A 周期性同步注册 consists of:A 标签, which is a DOMString.
注:周期性后台同步(Periodic Background Sync)不与后台同步(Background Sync)共享命名空间,因此同一 origin 可以同时拥有两种类型且使用相同标签的注册。
最小间隔(一个 long long),用于指定周期性同步应发生的最小间隔(以毫秒为单位)。最小间隔 是对用户代理的建议。
注:periodicsync 事件 实际触发的间隔必须大于或等于此值。
An 锚点时间(一个时间戳),表示此periodicsync 事件 上一次为该 周期性同步注册 触发的时间,或初始注册的时间。
A 状态,其值为
"pending"、"firing"、"suspended" 或
"reregistered-while-firing" 之一。初始值为 "pending"。
4.2. 周期性同步调度器
The 周期性同步调度器 负责调度periodicsync 事件 的触发。 响应这些触发器,调度器要么安排延迟处理以在将来的适当时间触发periodicsync 事件,要么取消此类调度。The 针对 origin 的有效最小同步间隔 origin(一个 origin),是 针对任何 origin 的最小周期性同步间隔 加上用户代理为该 origin 定义的某个值。
注:用户代理定义的该值可能基于用户与该 origin 的互动程度。每次调用 针对 origin 的有效最小同步间隔 时,这个值可以不同。
调度器会 处理周期性同步注册。
注:当没有 活动的周期性同步注册 时,浏览器可能会暂停此处理循环以节省资源。
4.3. 常量
As recommended in § 5 Privacy Considerations and § 6 Resource Usage, the user agent SHOULD also define:-
针对任何 origin 的最小周期性同步间隔,一个 long long,表示任一给定 origin 的 periodicsync 事件 之间的最小间隔,且,
-
跨 origin 的最小周期性同步间隔,一个 long long,表示所有 origin 之间 periodicsync 事件 之间的最小间隔。
跨 origin 的最小周期性同步间隔 必须大于或等于 针对任何 origin 的最小周期性同步间隔。 如果未定义,这些值被设置为 43200000(以毫秒计,即十二小时)。
注:需要两种频率上限,因为对每个 origin 遵守 针对任何 origin 的最小周期性同步间隔 的限制,仍可能导致浏览器非常频繁地触发 periodicsync 事件。例如,当存在许多针对不同 origin 的 周期性同步注册 时,就可能发生这种情况。跨 origin 的最小周期性同步间隔 确保了触发这些事件的全局上限。
用户代理可以定义一个 最大重试次数,一个数字,允许用于每个 periodicsync 事件。 在选择此值时,用户代理应确保尝试 最大重试次数 所需的时间数量级小于 针对任何 origin 的最小周期性同步间隔。如果未定义,则该值为零。
5. 隐私考虑
5.1. 权限
Periodic Background Sync 仅在为具有PermissionState
的 PermissionDescriptor
且其 name
为 "periodic-background-sync" 的权限状态为 granted
时可用。
此外,用户代理应当为用户提供禁用 Periodic Background Sync 的方式。
当 Periodic Background Sync 被禁用时,periodicsync 事件不得向受此权限影响的 周期性同步注册 派发。(参见 § 7.2 响应权限撤销。)
5.2. 位置追踪
在 periodicsync event 内发起的 fetch 请求在 后台运行 时, 可能在用户离开页面后向服务器暴露客户端的 IP 地址。用户代理应当通过限制重试次数和 periodicsync 事件 的持续时长来减少网站能够追踪用户位置的时间。此外,用户代理还应当通过限制对一个 origin 以及跨 origins 的 periodicsync 事件 的频率,来限制持久的位置信息追踪。5.3. 历史泄露
在 periodicsync 事件 内发起的 fetch 请求在 后台运行 时, 可能会向与创建该 周期性同步注册 所用网络不同的网络中的中间设备泄露关于客户端导航历史的信息。 例如,客户端可能访问了 https://example.com,该站点注册了一个 periodicsync 事件,但根据实现,该事件可能在用户已离开页面并切换网络后才触发。新网络上的中间设备可能会看到 periodicsync 事件 发起的 fetch 请求。由于这些 fetch 请求是使用 HTTPS 发起的,请求内容不会被泄露,但请求的目的地和域名可能会被泄露(通过 DNS 查询和请求的 IP 地址)。为防止这种浏览历史泄露,用户代理可以选择仅在创建该 周期性同步注册 时所用的网络上触发 periodicsync 事件,但这将以降低可用性为代价,因为无法机会性地进行同步。6. 资源使用
本节为非规范性内容。
网站在处理 periodicsync 事件 时,很可能会从网络下载资源。底层操作系统可能会启动用户代理来派发这些事件,并在预定义的时长内保持其活跃以允许处理事件。两者都会消耗电池。 用户代理应当限制这些事件的持续时间和频率,以在用户已离开页面时控制网站的资源使用。
对于大型资源,应当通过在 后台下载(background fetch) 中注册来下载,使用 BackgroundFetchManager
接口。
此外,用户代理应当考虑用户与该 origin 的参与度,以及任何用户指示临时减少数据消耗(例如数据节省模式),以调整 periodicsync 事件 的频率。
7. 算法
7.1. 处理周期性同步注册
当用户代理启动时,按 并行 运行以下步骤:-
重复执行:
-
令 firedPeriodicSync 为 false。
-
当 firedPeriodicSync 为 false 时:
-
等待某个用户代理定义的时间段。
注:这可以用于将不同 周期性同步注册 的同步合并到一次设备唤醒中。
-
等待直到处于 在线 状态。
-
对于每个不是 已注销 的 service worker registration registration, 将以下步骤 入队 到 registration 的 周期性同步处理队列:
-
令 origin 为与 periodicSyncRegistration 的 service worker registration 相关联的 origin。
-
如果 time of last fire[origin] + 针对该 origin 的 有效最小同步间隔 大于现在,则 继续。
-
对于 registration 的 活动周期性同步注册 中的每个 periodic sync registration periodicSyncRegistration:
-
如果 periodicSyncRegistration 的 anchor time + periodicSyncRegistration 的 minimum interval 大于现在,则 继续。
-
将 firedPeriodicSync 设为 true。
-
为 periodicSyncRegistration 触发 periodicsync 事件。
-
-
7.2. 响应权限撤销
为了对名为name
为 "periodic-background-sync" 的权限在某个 origin origin 上被撤销做出响应,用户代理必须将以下步骤排入 周期性同步处理队列:
-
对于 活动周期性同步注册 中的每个 periodic sync registration registration,如果其 service worker registration 与 origin 相同:
-
将 registration 从 active periodic sync registrations 中移除。
-
8. API 描述
8.1. 对 ServiceWorkerGlobalScope
接口的扩展
partial interface ServiceWorkerGlobalScope {attribute EventHandler ; };onperiodicsync
8.2. 对 ServiceWorkerRegistration
接口的扩展
ServiceWorkerRegistration/periodicSync
仅在一个当前引擎中可用。
OperaNoneEdge80+
Edge (Legacy)NoneIENone
Firefox for AndroidNoneiOS SafariNoneChrome for Android80+Android WebView80+Samsung Internet13.0+Opera MobileNone
[Exposed =(Window ,Worker )]partial interface ServiceWorkerRegistration {readonly attribute PeriodicSyncManager periodicSync ; };
ServiceWorkerRegistration
有一个 periodic sync manager(一个 PeriodicSyncManager)。
属性 periodicSync
的 getter 必须返回该 context object 的
periodic sync manager,初始为一个新的 PeriodicSyncManager,
其 service worker registration 为该 context object 的 service worker registration。
8.3.
PeriodicSyncManager
接口
仅在一个当前引擎中可用。
Opera67+Edge80+
Edge (Legacy)NoneIENone
Firefox for AndroidNoneiOS SafariNoneChrome for Android80+Android WebView80+Samsung Internet13.0+Opera Mobile57+
[Exposed =(Window ,Worker )]interface {PeriodicSyncManager Promise <undefined >register (DOMString ,tag optional BackgroundSyncOptions = {});options Promise <sequence <DOMString >>getTags ();Promise <undefined >unregister (DOMString ); };tag dictionary { [BackgroundSyncOptions EnforceRange ]unsigned long long = 0; };minInterval
PeriodicSyncManager
有一个 service worker registration(一个 service worker registration)。 仅在一个当前引擎中可用。
Opera67+Edge80+
Edge (Legacy)NoneIENone
Firefox for AndroidNoneiOS SafariNoneChrome for Android80+Android WebView80+Samsung Internet13.0+Opera Mobile57+
register(tag, options)
方法在被调用时,必须返回一个新的 promise
并将以下步骤 入队 到 周期性同步处理队列:
-
令 serviceWorkerRegistration 为与该上下文对象的
PeriodicSyncManager相关联的 service worker registration。 -
如果 serviceWorkerRegistration 的 active worker 为 null,则用
InvalidStateError拒绝 promise 并中止这些步骤。 -
如果名为
"periodic-background-sync"的权限的PermissionState不是granted, 则用NotAllowedError拒绝 promise 并中止这些步骤。 -
令 isBackground(布尔值)为 true。
-
对于与 serviceWorkerRegistration 的 origin 关联的每个 service worker clients 的 client:
-
如果 client 的 frame type 为 "
top-level" 或 "auxiliary",则将 isBackground 设为 false。
-
-
如果 isBackground 为 true,则用
InvalidAccessError拒绝 promise 并中止这些步骤。 -
令 currentRegistration 为在 serviceWorkerRegistration 的 active periodic sync registrations 中其 tag 等于 tag 的 periodic sync registration(若存在),否则为 null。
-
如果 currentRegistration 为 null:
-
令 newRegistration 为一个新的 periodic sync registration。
-
将 newRegistration 的 tag 设为 tag。
-
将 newRegistration 的 minimum interval 设为 options 的
minInterval成员。 -
将 newRegistration 的 state 设为 "
pending"。 -
将 newRegistration 的 service worker registration 设为 serviceWorkerRegistration。
-
将 newRegistration 的 anchor time 设为表示当前时间的时间戳。
-
将 newRegistration 添加到 serviceWorkerRegistration 的 active periodic sync registrations。
-
Resolve promise。
-
-
否则:
-
如果 currentRegistration 的 minimum interval 与 options 的
minInterval成员不同:-
将 currentRegistration 的 minimum interval 设为 options 的
minInterval成员。
-
-
否则,如果 currentRegistration 的 state 为 "
firing",则将 serviceWorkerRegistration 的 state 设为 "reregistered-while-firing"。 -
Resolve promise。
-
仅在一个当前引擎中可用。
Opera67+Edge80+
Edge (Legacy)NoneIENone
Firefox for AndroidNoneiOS SafariNoneChrome for Android80+Android WebView80+Samsung Internet13.0+Opera Mobile57+
getTags()
方法在被调用时,必须返回一个新的 promise
并将以下步骤 入队 到 周期性同步处理队列:
-
令 serviceWorkerRegistration 为与该上下文对象的
PeriodicSyncManager相关联的 service worker registration。 -
令 currentTags 为一个新的 列表。
-
对于 serviceWorkerRegistration 的每个 active periodic sync registrations 中的 registration,将 registration 的 tag 追加 到 currentTags。
-
Resolve promise 并返回 currentTags。
PeriodicSyncManager/unregister
仅在一个当前引擎中可用。
Opera67+Edge80+
Edge (Legacy)NoneIENone
Firefox for AndroidNoneiOS SafariNoneChrome for Android80+Android WebView80+Samsung Internet13.0+Opera Mobile57+
unregister(tag)
方法在被调用时,必须返回一个新的 promise
并将以下步骤 入队 到 周期性同步处理队列:
-
令 serviceWorkerRegistration 为与该上下文对象的
PeriodicSyncManager相关联的 service worker registration。-
令 currentRegistration 为在 serviceWorkerRegistration 的 active periodic sync registrations 中其 tag 等于 tag 的 periodic sync registration(若存在),否则为 null。
-
如果 currentRegistration 非空,则从 serviceWorkerRegistration 的 active periodic sync registrations 中移除 currentRegistration。
-
Resolve promise。
-
8.4. periodicsync 事件
PeriodicSyncEvent/PeriodicSyncEvent
仅有一个主流引擎支持。
Opera67+Edge80+
Edge (旧版)不支持IE不支持
Android 版 Firefox不支持iOS Safari不支持Android 版 Chrome80+Android WebView80+三星浏览器13.0+Opera Mobile57+
仅有一个主流引擎支持。
Opera67+Edge80+
Edge (旧版)不支持IE不支持
Android 版 Firefox不支持iOS Safari不支持Android 版 Chrome80+Android WebView80+三星浏览器13.0+Opera Mobile57+
dictionary :PeriodicSyncEventInit ExtendableEventInit {required DOMString ; }; [tag Exposed =ServiceWorker ]interface :PeriodicSyncEvent ExtendableEvent {(constructor DOMString ,type PeriodicSyncEventInit );init readonly attribute DOMString tag ; };
仅有一个主流引擎支持。
Opera67+Edge80+
Edge (旧版)不支持IE不支持
Android 版 Firefox不支持iOS Safari不支持Android 版 Chrome80+Android WebView80+三星浏览器13.0+Opera Mobile57+
8.4.1. 触发 periodicsync 事件
Note: 用户代理可以对PeriodicSyncEvent
的生命周期扩展和执行时间施加比一般 ExtendableEvent
更严格的时间限制。尤其是对 PeriodicSyncEvent
的任何重试可能有明显缩短的时间限制。
-
令 serviceWorkerRegistration 为 registration 的 service worker 注册。
-
如果 registration 不再属于 serviceWorkerRegistration 的 活跃 periodic sync 注册,则终止这些步骤。
-
令 retryCount 为 0。
-
将 registration 的 state 设为 "
firing"。 -
当条件为真,循环:
-
令 continue 为 false。
-
令 success 为 false。
-
触发功能事件 "
periodicsync",使用PeriodicSyncEvent于 serviceWorkerRegistration,其 tag 设置为 registration 的 tag。记 dispatchedEvent,类型为ExtendableEvent,表示派发出的 periodicsync 事件 并使用 dispatchedEvent 执行以下步骤: -
令 waitUntilPromise 为 等待全部 dispatchedEvent 的 延长生命周期 promises 的结果。
-
对于 fulfilled(满足) waitUntilPromise 时,执行以下步骤:
-
将 success 设为 true。
-
将 continue 设为 true。
-
-
对于 rejection(拒绝) waitUntilPromise 时,执行以下步骤:
-
将 continue 设为 true。
-
-
并行:
-
等待 continue 为 true。
-
令 origin 为与 registration 的 service worker 注册 关联的 源(origin)。
-
如果 success 为 true,则将 key 为 origin 的 最后触发时间 设置为当前时间。
-
如果 success 为 true,或 retryCount 大于 最大重试次数,或 registration 的 state 为 "
reregistered-while-firing",则:-
将 registration 的 state 设为 "
pending"。 -
将 registration 的 anchor time 设置为当前时间戳。
-
终止这些步骤。
-
-
-
将 retryCount 增加 1。
-
等待一个基于 retryCount 的小退避时间。
-