后台同步是一个新的 Web API,可让您将操作推迟到用户连接稳定后再执行。这样可以确保用户想要发送的内容都能实际发送。
问题
互联网是一个浪费时间的地方。如果不在互联网上浪费时间,我们就不会知道猫不喜欢花、变色龙喜欢泡泡泡,也不会知道我们的埃里克·比德尔曼是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 中,同时开发另一种变体:“定期后台同步”。通过定期后台同步,您可以请求受时间间隔、电池状态和网络状态限制的事件。当然,这需要用户授予权限,并且这些事件的触发时间和频率也取决于浏览器。换言之,新闻网站可能每小时请求同步一次,但浏览器可能知道您是在 07:00 才阅读该网站,因此系统每天 06:50 都会触发同步。这种想法比一次性同步稍微复杂一点,但它即将推出。
我们正在逐步将 Android 和 iOS 中的成功模式引入 Web,同时仍然保留让 Web 变得出色的功能!