后台同步是一种新的 Web API,可让您在用户建立稳定的网络连接之前延迟执行操作。这样可以确保用户想要发送的内容都能实际发送。
问题
互联网是消磨时间的好地方。如果不浪费时间上网,我们就不会知道猫不喜欢花、变色龙喜欢泡泡,也不会知道我们自己的 Eric Bidelman 是90 年代末的推杆高尔夫英雄。
但有时候,我们不想浪费时间。所需的用户体验大致类似于:
- 手机从口袋中取出。
- 实现小目标。
- 将手机放回口袋。
- 恢复生命值。
遗憾的是,这种体验经常会因网络连接不佳而中断。我们都经历过。您盯着白屏或旋转图标,知道自己应该放弃并继续生活,但还是再等待 10 秒,以防万一。10 秒后?什么都不会发生。
但为什么现在就放弃?您已经投入了时间,如果什么都得不到,那就太浪费了,因此您继续等待。此时,您想放弃,但您知道,如果您在那一刻放弃,那么所有内容都将在您放弃的那一刻之前加载完毕。
服务工件可让您从缓存中提供内容,从而解决页面加载问题。但是,如果网页需要向服务器发送内容,该怎么办?
目前,如果用户点击消息中的“发送”,他们必须盯着旋转图标,直到消息完成。如果用户尝试离开或关闭标签页,我们会使用 onbeforeunload
显示消息,例如“不行,我需要您再盯着这个旋转图标看一会儿。抱歉。”如果用户未连接到网络,我们会告诉用户“抱歉,您稍后必须返回并重试”。
这太荒唐了。借助后台同步功能,您可以取得更理想的成效。
解决方案
以下视频展示了Emojoy 的演示。它是一款渐进式 Web 应用,采用离线优先模式。该应用使用推送消息和通知,并使用后台同步。
如果用户在没有任何连接的情况下尝试发送消息,那么好消息是,当用户获得连接后,系统会在后台发送消息。
自 2016 年 3 月起,Chrome 49 及更高版本支持后台同步。您可以按照以下步骤查看其运作方式:
- 打开 Emojoy。
- 离线(使用飞行模式或前往当地的法拉第笼)。
- 输入消息。
- 返回主屏幕(可以选择关闭标签页或浏览器)。
- 连接到互联网。
- 消息在后台发送!
能够像这样在后台发送也可以带来可察觉的性能提升。应用无需对消息发送做太多处理,因此可以直接将消息添加到输出中。
如何请求后台同步
在真正的可扩展 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 及更高版本,然后执行以下操作:
- 前往任意一篇文章,例如 Chrome。
- 离线(使用飞行模式或加入像我这样的糟糕移动网络提供商)。
- 点击指向其他文章的链接。
- 系统应该会告知您页面未能加载(如果页面只是需要一段时间才能加载完毕,系统也会显示此消息)。
- 同意接收通知。
- 关闭浏览器。
- 切换为在线状态
- 当文章下载完毕、缓存并可供查看时,您会收到通知!
采用这种模式后,用户可以将手机放入口袋,继续自己的生活,同时知道手机会在提取所需内容时提醒他们。
权限
我展示的演示使用网络通知,此类通知需要权限,但后台同步本身不需要。
同步事件通常会在用户打开指向相应网站的网页时完成,因此要求用户授予权限会给用户带来不良体验。我们会限制何时可以注册和触发同步,以防止滥用。例如:
- 只有当用户打开了指向该网站的窗口时,您才能注册同步事件。
- 事件执行时间是有上限的,所以您不能每 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 上成功的模式引入到网站上,同时保留网站的优点!