通过 Periodic Background Sync API 获得更丰富的离线体验

在后台同步 Web 应用的数据,以获得更像应用的体验

Joe Medley
Joe Medley

您是否曾遇到以下任一情况?

  • 乘坐火车或地铁时网络连接不稳定或无法连接
  • 由于观看了太多视频,运营商对您施加了流量限制
  • 居住在带宽难以满足需求的国家/地区

如果您有过这样的经历,那么一定会对在网页上完成某些操作感到沮丧,并会想知道为什么在这些情况下平台专用应用的表现往往更好。特定于平台的应用可以提前提取新鲜内容,例如新闻报道或天气信息。即使在地下铁没有网络,您仍然可以阅读新闻。

借助定期后台同步,Web 应用可以定期在后台同步数据,使 Web 应用的行为更接近平台专用应用的行为。

试试看

您可以尝试使用实时演示版应用进行定期后台同步。在使用该应用之前,请确保:

  • 您使用的是 Chrome 80 或更高版本。
  • 您需要先安装 Web 应用,然后才能启用定期后台同步。

概念和用法

借助定期后台同步,您可以在启动渐进式 Web 应用或由服务工头支持的网页时显示新内容。它会在用户未使用应用或网页时在后台下载数据。这样可以防止应用在启动后在用户查看时刷新其内容。更重要的是,它可以防止应用在刷新之前显示内容旋转图标。

如果不进行定期后台同步,Web 应用必须使用其他方法下载数据。一个常见示例是使用推送通知唤醒服务 worker。系统会显示“有新数据可用”等消息来中断用户。更新数据本质上是一种副作用。您仍然可以选择使用推送通知接收真正重要的动态,例如重大突发新闻。

定期后台同步很容易与后台同步混淆。虽然它们的名称相似,但用例不同。除此之外,后台同步最常用于在之前的请求失败时将数据重新发送到服务器。

提升用户互动度

如果执行不当,定期后台同步可能会浪费用户资源。在发布之前,Chrome 会先对其进行试用,以确保其正确无误。本部分介绍了 Chrome 为使此功能尽可能实用而采取的一些设计决策。

Chrome 做出的第一个设计决策是,只有在用户将某款 Web 应用安装到其设备上并将其作为一款独立应用启动后,该应用才能使用定期后台同步功能。在 Chrome 的常规标签页情境中,无法使用定期后台同步。

此外,由于 Chrome 不希望未使用的或很少使用的 Web 应用无端消耗电量或流量,因此 Chrome 设计了定期后台同步功能,以便开发者必须通过为用户提供价值来赢得同步机会。具体而言,Chrome 使用网站互动度得分 (about://site-engagement/) 来确定是否可以为给定 Web 应用进行定期后台同步以及同步的频率。换句话说,除非互动度得分大于零,否则系统根本不会触发 periodicsync 事件,并且其值会影响 periodicsync 事件的触发频率。这样可以确保后台同步的应用仅限您正在使用的应用。

定期后台同步与热门平台上的现有 API 和做法有一些相似之处。例如,借助一次性后台同步和推送通知,在用户关闭网页后,Web 应用的逻辑(通过其服务工件)可以延长一段时间。在大多数平台上,用户安装的应用通常会在后台定期访问网络,以便在提供重要更新、预加载内容、同步数据等方面提供更好的用户体验。同样,定期后台同步还会延长 Web 应用逻辑的生命周期,使其按固定时间运行(每次可能需要几分钟)。

如果浏览器允许这种情况频繁发生且不受限制,可能会导致一些隐私问题。下面介绍了 Chrome 如何针对定期后台同步解决此风险:

  • 后台同步活动仅在设备之前连接过的网络上发生。Chrome 建议您仅连接到由可信方运营的网络。
  • 与所有互联网通信一样,定期进行的后台同步会显示客户端的 IP 地址、其所连接的服务器以及该服务器的名称。为了将此类情况的暴露程度大致降低到应用仅在前台运行时同步的情况,浏览器会根据用户使用该应用的频率来限制应用的后台同步频率。如果用户停止频繁与应用互动,定期后台同步将停止触发。与平台专用应用的现状相比,这是一个明显的改进。

何时可以使用?

使用规则因浏览器而异。总结上述内容,Chrome 对定期后台同步提出了以下要求:

  • 特定的用户互动度得分。
  • 存在之前使用的网络。

同步时间由系统控制,开发者无法控制。同步频率将与应用的使用频率保持一致。(请注意,平台专用应用目前不会执行此操作。)它还会考虑设备的电源和连接状态。

何时应使用此功能?

当您的服务工件唤醒以处理 periodicsync 事件时,您有机会请求数据,但没有义务这样做。在处理该事件时,您应考虑网络状况和可用存储空间,并相应地下载不同数量的数据。您可以使用以下资源来帮助您解决问题:

权限

安装服务工件后,请使用 Permissions API 查询 periodic-background-sync。您可以通过窗口或服务工件上下文执行此操作。

const status = await navigator.permissions.query({
  name: 'periodic-background-sync',
});
if (status.state === 'granted') {
  // Periodic background sync can be used.
} else {
  // Periodic background sync cannot be used.
}

注册定期同步

如前所述,定期后台同步需要服务工作线程。使用 ServiceWorkerRegistration.periodicSync 检索 PeriodicSyncManager,然后对其调用 register()。注册时需要提供标记和最小同步间隔 (minInterval)。标记用于标识已注册的同步,以便注册多个同步。在以下示例中,标记名称为 'content-sync'minInterval 为一天。

const registration = await navigator.serviceWorker.ready;
if ('periodicSync' in registration) {
  try {
    await registration.periodicSync.register('content-sync', {
      // An interval of one day.
      minInterval: 24 * 60 * 60 * 1000,
    });
  } catch (error) {
    // Periodic background sync cannot be used.
  }
}

验证注册

调用 periodicSync.getTags() 可检索注册标记数组。以下示例使用代码名称来确认缓存更新处于活动状态,以免再次更新。

const registration = await navigator.serviceWorker.ready;
if ('periodicSync' in registration) {
  const tags = await registration.periodicSync.getTags();
  // Only update content if sync isn't set up.
  if (!tags.includes('content-sync')) {
    updateContentOnPageLoad();
  }
} else {
  // If periodic background sync isn't supported, always update.
  updateContentOnPageLoad();
}

您还可以使用 getTags() 在 Web 应用的设置页面中显示有效注册的列表,以便用户启用或停用特定类型的更新。

响应定期后台同步事件

如需响应定期后台同步事件,请向您的服务工作器添加 periodicsync 事件处理脚本。传递给它的 event 对象将包含与注册期间使用的值匹配的 tag 参数。例如,如果定期后台同步已注册为名称为 'content-sync' 的任务,则 event.tag 将为 'content-sync'

self.addEventListener('periodicsync', (event) => {
  if (event.tag === 'content-sync') {
    // See the "Think before you sync" section for
    // checks you could perform before syncing.
    event.waitUntil(syncContent());
  }
  // Other logic for different tags as needed.
});

取消注册同步

如需结束已注册的同步,请使用要取消注册的同步的名称调用 periodicSync.unregister()

const registration = await navigator.serviceWorker.ready;
if ('periodicSync' in registration) {
  await registration.periodicSync.unregister('content-sync');
}

接口

下面简要介绍了 Periodic Background Sync API 提供的接口。

  • PeriodicSyncEvent。在浏览器选择的时间传递给 ServiceWorkerGlobalScope.onperiodicsync 事件处理脚本。
  • PeriodicSyncManager。注册和取消注册定期同步,并为已注册的同步提供标记。从 ServiceWorkerRegistration.periodicSync` 属性检索此类的实例。
  • ServiceWorkerGlobalScope.onperiodicsync。注册处理脚本以接收 PeriodicSyncEvent
  • ServiceWorkerRegistration.periodicSync。返回对 PeriodicSyncManager 的引用。

示例

更新内容

以下示例使用定期后台同步来下载和缓存新闻网站或博客的最新文章。请注意标记名称,它表示这是哪种类型的同步 ('update-articles')。对 updateArticles() 的调用封装在 event.waitUntil() 中,以便在下载和存储文章之前,服务工作器不会终止。

async function updateArticles() {
  const articlesCache = await caches.open('articles');
  await articlesCache.add('/api/articles');
}

self.addEventListener('periodicsync', (event) => {
  if (event.tag === 'update-articles') {
    event.waitUntil(updateArticles());
  }
});

向现有 Web 应用添加定期后台同步

这组更改是向现有 PWA 添加定期后台同步所需的。此示例包含一些实用的日志记录语句,用于描述 Web 应用中定期后台同步的状态。

调试

在本地进行测试时,很难获得定期后台同步的端到端视图。在调试 Web 应用行为时,有关有效注册、大致同步间隔时间和过去同步事件的日志信息可提供有价值的背景信息。幸运的是,您可以通过 Chrome DevTools 中的一项实验性功能找到所有这些信息。

录制本地活动

开发者工具的定期后台同步部分围绕定期后台同步生命周期中的关键事件进行整理:注册同步、执行后台同步和取消注册。如需获取与这些事件相关的信息,请点击开始录制

DevTools 中的“Record”按钮
DevTools 中的“录制”按钮

记录期间,DevTools 中会显示与事件对应的条目,并为每个事件记录上下文和元数据。

已记录的定期后台同步数据示例
已记录的定期后台同步数据示例

启用一次后,该功能最多会保持启用状态三天,这样开发者工具就可以捕获有关可能发生的后台同步(甚至是数小时后发生的同步)的本地调试信息。

模拟事件

虽然记录后台活动会很有帮助,但有时您可能希望立即测试 periodicsync 处理脚本,而无需等待事件按其正常节奏触发。

您可以通过 Chrome DevTools 中“Application”面板内的 Service Workers 部分执行此操作。借助定期同步字段,您可以为事件提供要使用的标记,并按需要触发该事件多次。

“应用”面板的“Service Workers”部分会显示“定期同步”文本字段和按钮。

使用 DevTools 界面

从 Chrome 81 开始,您会在 DevTools 的应用面板中看到定期后台同步部分。

显示“定期后台同步”部分的“应用”面板