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),用户代理必须将以下步骤排入队列至周期性同步
处理队列:
-
对于活动的周期性同步注册中的每个周期性同步注册 registration,如果其服务工作线程 注册所关联的源与 origin 相同:
-
从活动的周期性同步 注册中移除 registration。
-
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
promise,并将以下步骤排入队列至周期性同步
处理队列:
-
令 serviceWorkerRegistration 为与服务工作线程 注册相关联的上下文 对象的
PeriodicSyncManager。 -
如果 serviceWorkerRegistration 的活动工作线程为 null,则使用
InvalidStateError拒绝 promise,并中止这些步骤。 -
如果一个
PermissionDescriptor(其name为"periodic-background-sync")的PermissionState不是granted, 则使用NotAllowedError拒绝 promise, 并中止这些步骤。 -
令 isBackground(一个布尔值)为 true。
-
对于 serviceWorkerRegistration 的源对应的服务工作线程客户端中的每个 client:
-
如果 client 的框架类型为 "
top-level" 或 "auxiliary",则将 isBackground 设置为 false。
-
-
如果 isBackground 为 true,则使用
InvalidAccessError拒绝 promise,并中止这些步骤。 -
令 currentRegistration 为 serviceWorkerRegistration 的活动的周期性同步注册中 周期性同步 注册,如果存在其标签等于 tag 的注册,则取该注册,否则为 null。
-
如果 currentRegistration 为 null:
-
令 newRegistration 为一个新的周期性同步注册。
-
将 newRegistration 的标签设置为 tag。
-
将 newRegistration 的最小间隔设置为 options 的
minInterval成员。 -
将 newRegistration 的状态设置为 "
pending"。 -
将 newRegistration 的服务工作线程 注册设置为 serviceWorkerRegistration。
-
将 newRegistration 的锚点时间设置为表示 当前时间的时间戳。
-
将 newRegistration 添加到 serviceWorkerRegistration 的活动的周期性同步 注册中。
-
兑现 promise。
-
-
否则:
-
如果 currentRegistration 的最小间隔与 options 的
minInterval成员不同:-
将 currentRegistration 的最小 间隔设置为 options 的
minInterval成员。
-
-
否则,如果 currentRegistration 的状态为 "
firing", 则将 serviceWorkerRegistration 的状态设置为 "reregistered-while-firing"。 -
兑现 promise。
-
仅在一个当前引擎中可用。
Opera67+Edge80+
Edge (Legacy)NoneIENone
Firefox for AndroidNoneiOS SafariNoneChrome for Android80+Android WebView80+Samsung Internet13.0+Opera Mobile57+
getTags()
方法时,必须返回一个新的 promise
promise,并将以下步骤排入队列至周期性同步
处理队列:
-
令 serviceWorkerRegistration 为与服务工作线程 注册,其与上下文 对象的
PeriodicSyncManager相关联。 -
令 currentTags 为一个新的列表。
-
对于 serviceWorkerRegistration 的活动的周期性同步注册中的每个 registration,将 registration 的标签 追加到 currentTags。
-
使用 currentTags兑现 promise。
PeriodicSyncManager/unregister
仅在一个当前引擎中可用。
Opera67+Edge80+
Edge (Legacy)NoneIENone
Firefox for AndroidNoneiOS SafariNoneChrome for Android80+Android WebView80+Samsung Internet13.0+Opera Mobile57+
unregister(tag)
方法时,必须返回一个新的 promise
promise,并将以下步骤排入队列至周期性同步
处理队列:
-
令 serviceWorkerRegistration 为与服务工作线程 注册相关联的上下文 对象的
PeriodicSyncManager。-
令 currentRegistration 为 serviceWorkerRegistration 的活动的周期性同步 注册中的周期性同步注册,如果存在其标签等于 tag 的注册,则取该注册,否则为 null。
-
如果 currentRegistration 不为 null,则从 serviceWorkerRegistration 的活动的周期性同步 注册中移除 currentRegistration。
-
兑现 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 的小退避时间。
-