后台同步简介

杰克·阿奇博尔德
Jake Archibald

后台同步是一种新的网络 API,可让您推迟操作,直到用户连接稳定。这可确保用户想要发送的任何内容都会实际发送。

问题

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

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

  1. 从口袋里拿出手机。
  2. 实现次要目标。
  3. 将手机放回口袋中。
  4. 继续生活。

遗憾的是,这种体验经常因网络连接不佳而中断。我们所有人都有过这样的经历。你盯着白色的屏幕或旋转的图标,你知道你应该放弃,继续生活,但你又给了 10 秒,以备不时之需。10 秒后?什么都不会发生。

可为什么现在放弃呢?您已经投入了时间,所以什么都没走光是白白浪费,所以您继续等待。到此刻,您放弃,但您知道的第二次是:在只有您等候的情况下,一切内容才会加载。

Service Worker 通过让您从缓存提供内容来解决网页加载问题。但是,当网页需要向服务器发送内容时,该怎么办呢?

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

太垃圾了。后台同步可让您获得更好的体验。

解决方案

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

如果用户在网络连接为零时尝试发送消息,幸运的是,消息会在用户连接到网络后在后台发送。

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

  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 个单独的同步事件,只需使用唯一的代码即可!

这个简单的演示只完成了最基本的操作;它使用同步事件来显示通知。

我可以将后台同步用于哪些用途?

理想情况下,您可以使用它来安排任何您关注的超出页面生命周期的数据的发送时间。聊天消息、电子邮件、文档更新、设置更改、照片上传...任何想要访问服务器的内容,即使用户离开或关闭标签页也不受影响。页面可以将这些元素存储在 indexDB 中的“发件箱”存储区中,然后由 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 中成功的模式引入到网络,同时仍然保留使网络变得优秀的因素!