后台同步简介

Jake Archibald
Jake Archibald

后台同步是一种新的 Web API,可让您在用户建立稳定的网络连接之前延迟执行操作。这样可以确保用户想要发送的内容都能实际发送。

问题

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

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

  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 中,同时开发另一种变体:“定期后台同步”。借助定期后台同步,您可以请求受时间间隔、电池状态和网络状态限制的事件。当然,这需要用户授予权限,并且这些事件的触发时间和频率也取决于浏览器。换句话说,新闻网站可以请求每小时同步一次,但浏览器可能知道您只会在 7:00 阅读该网站,因此会在每天 6:50 触发同步。与一次性同步相比,此想法还需要一些时间才能实现,但我们会努力实现。

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