后台同步简介

Jake Archibald
Jake Archibald

发布时间:2015 年 12 月 8 日

后台同步是一种 Web API,可让您延迟执行操作,直到用户拥有稳定的连接。这有助于您支持用户尽快发送他们想发送的任何文件。

Browser Support

  • Chrome: 89.
  • Edge: 89.
  • Firefox: not supported.
  • Safari: not supported.

Source

问题

互联网是消磨时间的好去处。如果不浪费时间上网,我们就不会知道猫不喜欢花变色龙喜欢泡泡,也不会知道 Eric Bidelman90 年代末的推杆高尔夫英雄

但有时,我们只是不想浪费时间。理想的用户体验更像是:

  1. 手机不在口袋中。
  2. 达成次要目标。
  3. 手机放回口袋。
  4. 恢复生活。

遗憾的是,糟糕的网络连接经常会破坏这种体验。我们都有过这样的经历。您正盯着白屏或旋转微标,知道自己应该放弃并继续生活,但您还是再等了 10 秒,以防万一。10 秒后会发生什么?什么都不会发生。

但为什么要现在放弃?您已经投入了时间,如果一无所获地离开,那将是一种浪费,因此您继续等待。此时,您放弃,但您知道,一旦放弃,就意味着您错过了在等待片刻后加载所有内容的机会。

Service worker 可让您从缓存中提供内容,从而解决网页加载问题。但如果网页需要向服务器发送内容,该怎么办?

目前,如果用户点击消息中的“发送”,则必须盯着微调器,直到操作完成。如果用户尝试离开或关闭标签页,我们会使用 onbeforeunload 显示一条消息,例如“不行,您需要再盯着这个微调器看一会儿。对不起”。如果用户没有网络连接,我们会告知用户“抱歉,必须稍后回来重试”。

后台同步功能可让您更好地使用 Google 日历。

解决方案

以下视频展示了 Emojoy,这是一个仅使用表情符号的聊天演示。它是一款渐进式 Web 应用,采用离线优先模式。该应用使用推送消息和通知,并使用后台同步。

如果用户在没有网络连接的情况下尝试发送消息,那么幸运的是,一旦用户获得网络连接,系统就会在后台发送该消息。

像这样能够在后台发送数据,也能带来感知到的性能提升。应用无需对消息发送进行如此复杂的处理,因此可以直接将消息添加到输出中。

Chrome 49 及更高版本支持后台同步。

如何请求后台同步

按照真正的可扩展 Web 风格,这是一项低级功能,可让您自由地执行所需操作。您要求在用户有连接时触发事件,如果用户已有连接,则立即触发。然后,您监听该事件并执行所需操作。

与推送消息类似,它使用 service worker 作为事件目标,因此即使网页未打开,它也能正常运行。如需开始同步,请在网页中注册同步:

// Register your service worker:
navigator.serviceWorker.register('/sw.js');

// Then later, request a one-off sync:
navigator.serviceWorker.ready.then(function(swRegistration) {
  return swRegistration.sync.register('myFirstSync');
});
 ```

Then listen for the event in `/sw.js`:

```js
self.addEventListener('sync', function(event) {
  if (event.tag == 'myFirstSync') {
    event.waitUntil(doSomeStuff());
  }
});

这样就大功告成了!doSomeStuff() 应返回一个 promise,指示其尝试执行的操作是成功还是失败。如果 promise 得到兑现,则同步完成。如果失败,系统会安排另一次同步重试。重试同步也会等待连接,并采用指数退避算法。

同步的标记名称(示例中的“myFirstSync”)对于给定的同步应是唯一的。如果您注册的同步使用的标记与待处理的同步相同,则该同步会与现有同步合并。这意味着,您可以在用户每次发送消息时注册一次“清空发件箱”同步,但如果用户在离线时发送了 5 条消息,那么当用户变为在线状态时,您只会获得一次同步。如需获得 5 个单独的同步事件,请使用唯一标记。

以下演示使用同步事件来显示通知。

用于后台同步

理想情况下,您可以使用它来安排任何您希望在网页生命周期结束后发送的数据。聊天消息、电子邮件、文档更新、设置更改、照片上传或您希望到达服务器的任何内容,即使在用户离开或关闭标签页后也是如此。网页可以将这些消息存储在 indexedDB 中的“发件箱”存储区中,然后 Service Worker 会检索并发送这些消息。

不过,您也可以使用它来提取少量数据。

离线维基百科演示

这是我为大幅提升网页加载速度创建的离线维基百科演示。此后,我向其中添加了一些后台同步功能。

亲自尝试一下:

  1. 请让浏览器保持打开状态,并停留在该标签页中。
  2. 使用飞行模式或关闭 Wi-Fi 来离线。
  3. 点击指向其他文章的链接。
  4. 系统应告知您页面加载失败(如果页面只是需要一段时间才能加载,也会显示此消息)。
  5. 同意接收通知。
  6. 关闭浏览器。
  7. 切换为在线状态
  8. 当文章下载完毕、缓存完毕并可供查看时,您会收到通知!

使用此模式,用户可以将手机放在口袋里,继续正常生活,因为他们知道,当手机获取到所需内容时,会提醒他们。

权限

我展示的演示使用网页通知,这需要获得权限,但后台同步本身不需要。

同步事件通常会在用户打开网站页面时完成,因此要求用户授予权限会带来糟糕的体验。相反,我们会限制何时可以注册和触发同步,以防止滥用。例如:

  • 只有当用户打开了网站窗口时,您才能注册同步事件。
  • 事件执行时间有限制,因此您无法使用它们每隔 x 秒 ping 一次服务器、挖掘比特币或其他任何操作。

当然,这些限制可能会根据实际使用情况放宽或收紧。

采用渐进增强的方式

在等待后台同步成为基准的同时,您可以将其用作渐进式增强功能:

if ('serviceWorker' in navigator && 'SyncManager' in window) {
  navigator.serviceWorker.ready.then(function(reg) {
    return reg.sync.register('tag-name');
  }).catch(function() {
    // system was unable to register for a sync,
    // this could be an OS-level restriction
    postDataFromThePage();
  });
} else {
  // serviceworker/sync not supported
  postDataFromThePage();
}

如果 Service Worker 或后台同步不可用,只需像现在一样发布网页中的内容即可。

即使用户似乎具有良好的连接,也值得使用后台同步,因为它可以防止在发送数据期间发生导航和关闭标签页的情况。

未来展望

我们的目标是在 2016 年上半年将后台同步功能发布到 Chrome 的稳定版中,同时开发一种变体“周期性后台同步”。借助周期性后台同步,您可以请求受时间间隔、电池状态和网络状态限制的事件。当然,这需要用户授予权限,并且浏览器也会决定这些事件的触发时间和频率。换句话说,新闻网站可以请求每小时同步一次,但浏览器可能知道您只会在 07:00 阅读该网站,因此同步会在每天 06:50 触发。这种想法比一次性同步更进一步,但很快就会实现。

我们正逐步将 Android 和 iOS 上的成功模式引入 Web,同时保留 Web 的优势!