当咱们在一些地下停车场,或者在火车上、电梯等没法避免的信号不稳定的场所,使用网站应用处理一些表单操做或者上传数据的操做时,面临的将是网络链接错误的响应,使用户的操做白费。html
而此刻 PWA 的 Sync API 就很好的解决了这个问题,让用户处理一些数据上传的操做时,无需关系网络环境,全部相关操做均会完成。Sync API 也是 PWA 离线里面的重要一环,下面就说一块。数组
SyncManager 接口提供了用于注册和获取 Sync 注册的接口。Sync 是一个简单且很是实用的功能。浏览器
经过 ServiceWorkerRegistration 接口的 sync 进行获取:网络
navigator.serviceWorker.ready.then(reg => {
console.log(reg.sync)
})
复制代码
SyncManager.registerasync
用于注册一个 sync tag,tag 按照本身的需求设置。fetch
语法:网站
SyncManager.register(DOMString tag).then(function(void) { ... })
复制代码
返回 void 的 Promise。ui
SyncManager.getTagsspa
用于获取已注册且未完成的 sync tag(完成后的 sync tag 会自动今后列表中删除)。.net
语法:
SyncManager.getTags().then(function(tags[]) { ... })
复制代码
返回注册 syn tag 的字符串数组的 Promise。
onsync
注册后的 Sync tag 会触发 ServiceWorkerGlobalScope 下的 onsync 事件。
此事件值包含两个属性:
tag
:返回触发这次事件的注册 Sync tag 的 tag 值。lastChance
:若是浏览器在尝试屡次后还未成功,当 lastChance 为 true
时表示再也不尝试,且这次 sync tag 删除。从注册一个 Sync tag 到这个 Sync tag 完成,会经历三个阶段:
SyncManager.register(tag)
后,会当即注册 sync,并将注册后的 sync tag 放入 sync 的注册列表中(能够经过SyncManager.getTags()
获取到),而后会判断当前的网络环境,只有网络在线的状况下,注册的 Sync 才会发出 sync 事件,而后当 SyncEvent.waitUntil()
中 Promise 为 reject 时将会周期性的触发 onsync 事件,直到不为 reject 才会完成 Sync tag,而后将相关 tag 清除。
在 Chrome 下,当 SyncEvent.waitUntil()
中的参数值一直为 Promise reject 时,会最多触发三次 onsync 事件,每次的周期时间至少为 5 分钟。
注意:sync 事件中的处理结果必须放在 SyncEvent.waitUntil() 中,不然会当即完成 Sync。
注意:上次中的重试次数和周期时间是 Chrome 环境下的体现,具体次数和周期标准中未规范,能够 e.lastChance 来判读,处理最后一次的相关逻辑。
能够经过 DevTools 里的 Background Services 查看 Sync 的执行过程:
SyncManager 自己只是一个简单的 API,sync 事件中也只有两个只读属性,因此基于 Sync 来作的同步数据,比较好的方式搭配 IndexDB 来实现,下面两个场景也是基于 IndexDB。
这种场景下,相关场景的数据请求先写入 IndexDB 中,而后注册 Sync,在 onsync 中根据相关 tag 来处理 IndexDB 中的数据请求。
下面是一个聊天应用的场景
index.html:
btnSend.addEventListener('click', async () => {
await db.add('chatList', { msg, time, useId});
reg = await navigator.serviceWorker.ready;
reg.sync.register('send_chat');
})
复制代码
sw.js
self.addEventListener('sync', e => {
e.tag == 'send_chat' && e.waitUntil(new Promise.then(async (res, rej) => {
var allData = await db.getAll('chatList');
return Promise.all(allData.map(data => fetch(data)));
}))
})
复制代码
这个场景能够针对于某些特定请求,先让它正常发送网络请求,若是失败则将失败的请求放到相关的 IndexDB 中,并设定这条网络请求可尝试的有效期,有效期内均会重拾。
关于 sync 的周期上面也说过,在 Chrome 下最多尝试三次,本场景下的这种需求,须要相关的 sync tag 一直处理可用状态,因此须要对这一层进行修改知足需求。
例如点赞场景
index.html
btnLike.addEventListener('click', () => {
reg = await navigator.serviceWorker.ready;
reg.sync.register('like’);
fetch(data).catch(e => {
db.add('likeList', {data, lastTime: 12938749138}); // 有效期时间戳
})
})
复制代码
sw.js
self.addEventListener("sync", e => {
if (e.tag == "send_chat") {
e.waitUntil(
new Promise.then(async (res, rej) => {
while (db.get("likeList")[0]) {
var data = db.get("likeList")[0];
try {
if(data.lastTime > Date.now()) {
db.remove('likeList', data)
} else {
await fetch(data);
db.remove('likeList', data)
}
} catch (err) {
if(e.lastChance == true) { // 若是最后一次尝试机会,则从新注册,保证一直有效
self.registration.sync.register('like')
}
}
}
})
);
}
});
复制代码
注意:上面代码中的 db 为模拟的伪代码。
经过 Sync API 的支持,网站应用能够较大的离线化,提高用户的体验度和应用的可靠性。这样用户在网络链接失败的状况下也能上传表单、点赞评论文章、发送消息等等,为用户带来积极的影响。也意味着 Web 应用更加接近原生应用的体验效果。
博客名称:王乐平博客
CSDN博客地址:blog.csdn.net/lecepin