后台同步简介

Jake Archibald
Jake Archibald

后台同步是一个新的 Web API,可让您将操作推迟到用户连接稳定后再执行。这样可以确保用户想要发送的内容都能实际发送。

问题

互联网是一个浪费时间的地方。如果不在互联网上浪费时间,我们就不会知道猫不喜欢花变色龙喜欢泡泡泡,也不会知道我们的埃里克·比德尔曼90 年代末的推杆高尔夫大师

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

  1. 手机从口袋中取出。
  2. 实现小目标。
  3. 将手机放回口袋。
  4. 恢复生命值。

遗憾的是,这种体验经常会因网络连接不佳而中断。我们所有人都有过这样的经历。您盯着白屏或旋转图标,知道自己应该放弃并继续生活,但还是再等待 10 秒,以防万一。10 秒后?什么都不会发生。

可是为什么现在放弃呢?您已经投入了时间,如果什么都得不到,那就太浪费了,因此您继续等待。此时,您放弃,但您知道,如果您在那一刻放弃,那么所有内容都将在您放弃的那一刻之前加载完毕。

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

目前,如果用户点击消息中的“发送”,他们必须盯着旋转图标,直到消息完成。如果他们尝试离开或关闭该标签页,我们会使用 onbeforeunload 显示一条消息:“不,我需要您再凝视一下这个旋转图标。抱歉。”如果用户未连接到网络,我们会告诉用户“抱歉,您稍后必须返回并重试”。

这太荒唐了。后台同步功能可助您事半功倍。

解决方案

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

如果用户在没有任何连接的情况下尝试发送消息,那么好消息是,当用户获得连接后,系统会在后台发送消息。

自 2016 年 3 月起,Chrome 49 及更高版本支持后台同步。您可以按照以下步骤查看操作:

  1. 打开 Emojoy
  2. 离线(使用飞行模式或前往当地的法拉第笼)。
  3. 输入消息。
  4. 返回主屏幕(可选择关闭标签页或浏览器)。
  5. 连接到网络。
  6. 在后台发送消息!

能够以这种方式在后台发送数据,也能提升用户体验。应用无需对消息发送做太多处理,因此可以直接将消息添加到输出中。

如何请求后台同步

在真正的可扩展 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,指示其尝试执行的任何操作的成功/失败情况。如果它执行完毕,则同步完成。如果同步失败,系统会安排再次同步。重试同步也会等待连接,并采用指数退避算法。

对于给定的同步,同步的标记名称(上例中的 myFirstSync)应是唯一的。如果您注册的同步使用的是与待处理同步相同的标记,则该同步会与现有同步合并。这意味着,您可以注册在用户每次发送邮件时执行“清空收件箱”同步,但如果用户在离线状态下发送了 5 封邮件,那么当他们上线后,您只会收到一次同步。如果您想要 5 个单独的同步事件,只需使用唯一的代码即可!

以下是一个简单的演示,它只会执行最低限度的操作;它使用同步事件显示通知。

后台同步有何用途?

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

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

另一个演示!

这是我为推动网页加载而制作的离线维基百科演示。我为其添加了一些后台同步魔法。

您可以亲自试用一下。确保您使用的是 Chrome 49 及更高版本,然后执行以下操作:

  1. 前往任意一篇文章,例如 Chrome
  2. 离线(使用飞行模式或加入像我这样的糟糕移动网络提供商)。
  3. 点击指向其他文章的链接。
  4. 系统应该会告知您页面未能加载(如果页面只是需要一段时间才能加载完毕,系统也会显示此消息)。
  5. 同意接收通知。
  6. 关闭浏览器。
  7. 切换为在线状态
  8. 当文章下载完毕、缓存并可供查看时,您会收到通知!

采用这种模式后,用户可以将手机放入口袋,继续自己的生活,同时知道手机会在提取所需内容时提醒他们。

权限

我演示的演示使用的是网络通知,需要权限,但后台同步本身不需要权限。

同步事件通常会在用户已打开网站页面时完成,因此需要用户许可会给他们带来糟糕的体验。而是会限制何时可以注册和触发同步,以防止滥用行为。例如:

  • 您只能在用户打开网站的窗口时注册同步事件。
  • 事件执行时间是有上限的,因此您无法使用这些事件每 x 秒 ping 一次服务器、挖掘比特币或执行其他操作。

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

采用渐进增强的方式

所有浏览器都支持后台同步还需要一段时间,尤其是 Safari 和 Edge 尚不支持 Service Worker。不过,渐进式增强功能可以帮助您解决此问题:

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 变得出色的功能!