PWA(Progressive Web App)入门系列:Sync 后台同步
前言
當我們在一些地下停車場,或者在火車上、電梯等無法避免的信號不穩定的場所,使用網站應用處理一些表單操作或者上傳數據的操作時,面臨的將是網絡連接錯誤的響應,使用戶的操作白費。
而此刻 PWA 的 Sync API 就很好的解決了這個問題,讓用戶處理一些數據上傳的操作時,無需關系網絡環境,所有相關操作均會完成。Sync API 也是 PWA 離線里面的重要一環,下面就說一塊。
SyncManager API
SyncManager 接口提供了用于注冊和獲取 Sync 注冊的接口。Sync 是一個簡單且非常實用的功能。
通過 ServiceWorkerRegistration 接口的 sync 進行獲取:
navigator.serviceWorker.ready.then(reg => {console.log(reg.sync) })方法
SyncManager.register
用于注冊一個 sync tag,tag 按照自己的需求設置。
語法:
SyncManager.register(DOMString tag).then(function(void) { ... })返回 void 的 Promise。
SyncManager.getTags
用于獲取已注冊且未完成的 sync tag(完成后的 sync tag 會自動從此列表中刪除)。
語法:
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 完成,會經歷三個階段:
- Registered sync:注冊 sync。
- Dispatched sync event:發出 sync 事件。
- Sync completed:Sync 完成。
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。
1. 完全 Sync 化數據請求傳輸
這種場景下,相關場景的數據請求先寫入 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)));})) })2. 失敗請求的 Sync 化
這個場景可以針對于某些特定請求,先讓它正常發送網絡請求,如果失敗則將失敗的請求放到相關的 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博客地址:http://blog.csdn.net/lecepin
本作品采用知識共享署名-非商業性使用-禁止演繹 4.0 國際許可協議進行許可。總結
以上是生活随笔為你收集整理的PWA(Progressive Web App)入门系列:Sync 后台同步的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 资源
- 下一篇: 微博自媒体,一个新的生态