渐进式web应用开发-- 使用后台同步保证离线功能(六)

渐进式web应用开发-- 使用后台同步保证离线功能(六),第1张

概述阅读目录 一:什么是后台同步保证离线功能呢? 二:后台同步是如何实现的呢? 三:如何给sync事件传递数据? 四:在我们的项目中添加后台同步功能 回到顶部 一:什么是后台同步保证离线功能呢? 在我们做移动端开发也好,还是做PC端应用也好,我们经常会碰到填写表单这样的功能,如果我们的表单填写完成以后,我们点击提交,但是这个时候我突然进入了电梯,或者我们在高铁上做这么一个 *** 作,突然断网了,或者说我们的

阅读目录

一:什么是后台同步保证离线功能呢? 二:后台同步是如何实现的呢? 三:如何给sync事件传递数据? 四:在我们的项目中添加后台同步功能 回到顶部

一:什么是后台同步保证离线功能呢?

在我们做移动端开发也好,还是做PC端应用也好,我们经常会碰到填写表单这样的功能,如果我们的表单填写完成以后,我们点击提交,但是这个时候我突然进入了电梯,或者我们在高铁上做这么一个 *** 作,突然断网了,或者说我们的网络不好的情况下,那么一般的情况下会一直请求,当我们的请求超时的时候就会请求失败,或者说请求异常,最后就会提示我们网络异常这些信息,那么这样对于用户体验来说并不是很好,那么现在我们来理解下什么是后台同步保证离线功能呢?后台同步离线功能就是说当我们的网络不好的时候,我们点击提交按钮时,我们会保证该应用一定是成功的,不会提示网络异常这些信息,当网络连接失败的时候,我们会在前端页面显示一个提示,比如说,正在请求中,请稍微.... 这样的一个提示,当我们的网络恢复正常了,我们会重新去请求下该接口,那么我们这个应用就提示 *** 作成功状态了。

后台同步:它使得我们能够确保用户采取的任何 *** 作都能完成,不管用户的链接状态如何,甚至当用户点击提交后,直接关闭我们这个应用,不再回来,并且关闭浏览器,后台同步 *** 作也能够完成。

后台同步的优点:

1. 对于用户而言,能够信任我们的渐进式web应用能一直工作,这也意味者我们与传统的web开发是有区别的,我们可以实现原生应用类似的效果。

2. 对于企业来讲,让用户在链接失败的时候,也能够订火车票,订阅新闻或发送消息,对于这样的用户体验也会更好。

回到顶部

二:后台同步是如何实现的呢?

后台同步原理的实质是:它是将 *** 作从页面上下文中剥离开来,并且在后台运行。

通过将这些 *** 作放到后台,它就不会受到单个网页的影响,即使网页被关闭,用户连接会断开,甚至服务器有时候会出现故障,但是只要我们电脑上安装了浏览器,后台同步的 *** 作就不会消失,直到它成功完成为止。

1. 注册一个同步事件

使用后台同步很简单,我们首先要注册一个同步事件,如下代码:

navigator.serviceWorker.ready.then(function(registration) {  registration.sync.register(‘send-messages‘);});

如上代码可以在页面上运行,它获取了当前激活的service Worker 的 registration 对象,并注册了一个叫 send-messages 的sync事件。

现在,我们就可以将一个监听该同步事件的事件监听器添加到 service worker 中,该事件包含的逻辑将会在service worker 中执行,而不是在页面上执行的。

如下代码:

self.addEventListener("sync",function(event) {  if (event.tag === "send-messages") {    event.waitUntil(function(){      var sent = sendMessages();      if (sent) {        return Promise.resolve();      } else {        return Promise reject();      }    })  }});

2. 理解 SyncManager

我们上面已经注册了一个sync事件,并且在service worker中监听了该sync事件。
那么所有与sync事件的交互都是通过 SyncManager 来完成的。SyncManager是 service worker 的一个接口。它可以让我们注册sync事件,并且我们可以获取已经注册的sync事件列表。

访问 SyncManager

我们可以通过已经激活的service worker的registration对象来访问 SyncManager,在service worker里面,我们可以通过调用navigator.serviceWorker.ready 来访问当前激活的 service worker 的 registration对象,该方法会返回一个Promise对象,当成功时候我们可以拿到service worker的registration对象。

如下代码:

navigator.serviceWorker.ready.then(function(registration){});

如上代码,我们已经获得到了 registration 对象后,不管我们是在service worker上还是在页面上,和SyncManager交互现在都是一样的。

3. 注册事件

想要注册 sync事件,我们可以在 SyncManager中调用 register,传入一个我们想要注册的 sync事件名称。

比如我们想注册一个在service worker中叫 send-message的事件,我们可以使用如下代码:

self.registration.sync.register("send-message");

如果我们想在service-worker中想做一样的事情的话,我们可以使用如下代码:

navigator.serviceWorker.ready.then(function(registration) {  registration.sync.register("send-message");});

4. 理解Sync事件原理

SyncManager 维护了一个Sync事件标签列表,SyncManager只知道哪些事件被注册了,何时被调用,以及如何发送sync事件。

当我们下面任何一个事件发生的时候,SyncManager会给列表中的每一个注册事件名发送一个sync事件。

1) sync事件注册后会立即发送。
2)当用户离线变成在线的时候也会发送。
3)如果还有未完成的事件时,每隔几分钟会发送。

在service worker中,我们发送sync事件,那么该事件就可以被监听到,并且我们可以使用promise进行响应,如果我们的这个promise完成了,那么对应的sync注册会从 SyncManager中删除,如果promise拒绝了,那么我们的sync注册的事件就会保留在SyncManager中,并且每隔几分钟会在下一个同步机会进行重试。

5. 理解 sync事件中的事件名称

sync事件中的事件名称是唯一的。如果在SyncManager中使用一个已经被注册的事件名称继续来注册的话,那么SyncManager 会忽略它,比如说:我们正在构建一个邮件服务,每当用户发送消息的时候,我们可以把消息保存到 indexedDB的发件箱中,并且注册一个send-email-message这样的后台同步事件,那么我们的service worker可以包含一个事件监听器进行监听,它会遍历indexedDB发件箱中的每一条消息,尝试发送他们,并且当发送成功后,将会从 indexedDB队列中删除它,如果我们当中有某条消息并没有发送成功的话,那么该sync事件就会被拒绝,SyncManager将会在稍后再次发送该事件,但是该事件是我们上次事件中发送失败的那个事件。使用这种设置,我们永远不需要检查发件箱中是否存在消息,只要有未发送的电子邮件,sync事件就会保持注册,并且尝试清空我们发的发件箱。

5. 理解获取已经注册的sync事件列表

我们使用SyncManager的getTags()方法,就可以得到完整的已注册同步事件列表。该getTags()方法也会返回一个Promise对象,该promise对象完成后,会获得一个sync注册事件名称的数组。

在service-worker中,我们可以注册一个叫 hello-world的sync事件,然后将当前注册的完整事件列表打印在控制台中中;如下代码:

self.registration.sync.register("hello-world").then(function() {  return self.registration.sync.getTags();}).then(function(Tags) {  console.log(Tags);});

在我们的service worker中,我们首先通过使用 ready 获取 registration对象,也可以获取一样的结果,如下代码所示:

navigator.serviceWorker.ready.then(function(registration){  registration.sync.register(‘hello-world‘).then(function() {    return registration.sync.getTags();  }).then(function(Tags) {    console.log(Tags);  });});

6. 最后一次发生sync事件

在有些情况下,SyncManager可以会判断出尝试发送的sync事件已经多次失败,当发生这种情况的时候,SyncManager将会发送最后一次事件,给我们最后一次响应的机会,我们可以通过sync事件的lastChance属性来判断什么时候会发生这种情况,如下代码:

self.addEventListener("sync",event => {  if (event.tag === "hello-world") {    event.waitUntil(      // 调用 addReservation方法      addReservation().then(function(){        return Promise.resolve();      }).catch(function(error) {        if (event.lastChance) {          return removeReservation();        } else {          return Promise.reject();        }      })    )  }})
回到顶部

三:如何给sync事件传递数据?

在页面接口交互中,我们可能需要传递一些参数进去,比如说,发生一个消息的接口中,可能我们需要把消息文本发送过去,一个为帖子点赞的接口,我们需要把帖子ID的参数传递过去。但是当我们注册sync事件时,我们目前来看,我们之前只能传递事件名称,但是我们如何把一些对应的参数也传递给sync中的事件当中呢?

1. 在indexedDB中维护 *** 作队列

要想把一些参数传递过去,我们可以把这些参数先保存到我们的indexedDB中,然后,我们在service worker中的sync事件代码我们可以迭代该对象存储,并且在每个条目上执行所需的 *** 作,一旦 *** 作成功了,我们就可以把该实体从对象存储中删除掉。

现在我们来做个demo,我们现在需要把每一条消息可以添加到 message-queue对象存储中,然后我们注册一个 send-message 后台同步事件来处理,该事件会遍历 message-queue对象中的所有消息,依次将他们发送到网络中,如果当所有消息都发送成功的话,我们会依次将消息队列中的数据删除,因此对象存储就为空了。但是如果有任何一条消息没有发送成功的话,就会向sync事件返回一个拒绝的promsIE,SyncManager在稍后一段时间内会再次运行该sync事件。

如果我们之前使用如下代码,来请求一个接口,如下代码所示:

var sendMessage = function(subject,message) {  fetch(‘/new-message‘,{    method: ‘post‘,body: JsON.stringify({      subject: subject,msg: message    })  })};

现在我们使用service worker,需要把代码改成如下所示:

var triggerMessageQueueUpdate = function() {  navigator.serviceWorker.ready.then(function(registration) {    registration.sync.register("message-queue-sync");  });};var sendMessage = function(subject,message) {  addToObjectStore("message-queue",{    subject: subject,msg: message  });  triggerMessageQueueUpdate();};

然后我们需要在service worker中监听sync事件代码如下:

self.addEventListener("sync",function(event) {  if (event.target === ‘message-queue-sync‘) {    event.waitUntil(function() {      return getAllMessages().then(function(messages) {        return Promise.all(          messages.map(function(message) {            return fetch(‘/new-message‘,{              method: ‘post‘,body: JsON.stringify({                subject: subject,msg: message              })            }).then(function(){              return deleteMessageFromQueue(message);             })          })        )      })    })  }});

如上改写后的代码,首先我们会调用 addToObjectStore 这个方法来把消息保存到我们的key为 ‘message-queue‘ 当中,然后调用 triggerMessageQueueUpdate 这个方法,使用sync注册message-queue-sync这个事件,并且我们使用sync监听了该事件名称,然后我们使用了 getAllMessages 方法获取indexedDB的消息队列中的所有消息,并且最终返回了一个promise给sync事件,在该代码中,我们使用了Promise.all方法,在该方法内部,只有我们的消息发送成功后,我们才会使用 deleteMessageFromQueue方法来删除该消息,在我们的消息数组中,我们使用了map()方法遍历为每条消息发送一个promise对象.

2. 在indexedDB中维护请求队列

有时候在我们的项目中,我们需要实现本地存储架构来对对象状态进行跟踪,如果页面上有多个AJAX请求的话,我们可以使用service worker 在indexedDB中来维护请求队列,我们可以将网络上的每个请求存储到indexedDB中,然后该方法会注册一个sync事件,该事件会遍历对象存储中所有请求,并依次执行。

比如项目中有如下代码:

var sendMessage = function(subject,msg: message    })  })};var getRequest = function(ID) {  fetch(‘/like-post?ID=‘+ID);};

如上两个请求,我们使用service worker 换成如下代码:

var triggerRequestQueueSync = function() {  navigator.serviceWorker.ready.then(function(registration){    registration.sync.register("request-queue");  });};var sendMessage = function(subject,message) {  addToObjectStore("request-queue",{    url: ‘/new-message‘,method: ‘post‘,msg: message    })  });  triggerRequestQueueSync();};var getRequest = function(ID) {  addToObjectStore(‘request-queue‘,{    url: ‘/like-post?ID=‘ + ID,method: ‘get‘  });  triggerRequestQueueSync();};

如上代码,我们将所有的网络请求替换成如上的代码,将代表请求对象存储到 request-queue的对象存储中,这个存储中每个对象代表一个网络请求,接下来我们需要添加一个sync事件监听器到service worker中,它负责遍历 request-queue的所有请求,依次会发起一个网络请求,发送成功后,依次从对象存储中删除。如下代码所示:

self.addEventListener("sync",function(event) {  if (event.tag === "request-queue") {    event.waitUntil(function(){      return getAllObjectsFrom("request-queue").then(function(requests) {        return Promise.all(          requests.map(function(req) {            return fetch(req.url,{              method: req.method,body: req.body            }).then(function() {              return deleteRequestFromQueue(req); // 返回一个promise            })          })        )      });    })  }});

如上代码,如果一个请求发送成功了,就会从indexedDB中队列中删除掉,失败的请求会保留到队列中,并且返回被拒绝的promise,那么失败的promise会在请求队列的下一次sync事件中再次迭代。

3. 使用一种更简单的方式传递数据给事件名称

当我们需要传递一个简单的数据给sync函数时候,我们就不需要使用上面的indexedDB来存储数据,然后再service worker中依次遍历拿到该对象了,我们可以使用一种更简单的方式来解决如上的问题。我们之前的代码是这样的:

var likePost = function(postID) {  fetch("/like-post?ID="+postID);};

我们可以在service worker中使用如下代码来进行改造,如下代码所示:

var likePost = function(postID) {  navigator.serviceWorker.ready.then(function(registration){    registration.sync.register("like-post-"+postID);  });};

我们使用sync事件来监听上面的函数,代码如下:

self.addEventListener("sync",function(event) {  if (event.tag.startsWith("like-post-")) {      event.waitUntil(function(){      var postID = event.tag.slice(10);      return fetch(‘/like-post?ID=‘+postID);    })  }});
回到顶部

四:在我们的项目中添加后台同步功能

在我们项目中添加后台同步功能之前,我们还是来看下我们项目中的整个目录架构如下所示:

|----- service-worker-demo6|  |--- node_modules        # 项目依赖的包|  |--- public              # 存放静态资源文件|  | |--- Js|  | | |--- main.Js         # Js 的入口文件|  | | |--- store.Js        # indexedDB存储|  | | |--- myAccount.Js    |  | |--- styles|  | |--- images|  | |--- index.HTML        # HTML 文件|  |--- package.Json|  |--- webpack.config.Js|  |--- sw.Js

该篇文章是在上篇文章基础之上继续扩展的,如果想要看上篇文章,请点击这里

我们首先来看下我们 public/index.HTML 代码如下:

<!DOCTYPE HTML><HTML lang="en"><head>  <Meta charset="UTF-8">  <Title>service worker 实列</Title></head><body>  <div ID="app">222226666</div>  <img src="/public/images/xxx.jpg" />  <div style="cursor: pointer;color:red;Font-size:18px;padding:5px;border:1px solID #333;" ID="submit">点击我新增</div>  <div style="cursor: pointer;color:red;Font-size:18px;padding:5px;border:1px solID #333;" ID="update">点击我修改</div></body></HTML>

public/Js/myAccout.Js 代码如下(该代码的作用最主要是做页面业务逻辑代码)

import $ from ‘jquery‘;$(function() {  function renderHTMLFunc(obj) {    console.log(obj);  }  function updatedisplay(d) {    console.log(d);  };  var addStore = function(ID,name,age) {    var obj = {      ID: ID,name: name,age: age    };    addToObjectStore("store",obj);    renderHTMLFunc(obj);    $.getJsON("http://localhost:8081/public/Json/index.Json",obj,function(data) {      updatedisplay(data);    });  };  $("#submit").click(function(e) {    addStore(3,‘longen1‘,‘111‘);  });  $("#update").click(function(e) {    $.getJsON("http://localhost:8081/public/Json/index.Json",{ID: 1},function(data) {      updateInObjectStore("store",1,data);      updatedisplay(data);    });  });});

如上myAccout.Js代码,当我点击 ID 为 "submit" 的div元素的时候(我们可以假设这是一个form表单提交,这边为了演示这个作用懒得使用form表单来演示),当我点击该div元素的时候,我们的addStore函数会被调用,这个函数内部会调用 addToObjectStore()这个方法,这个函数会添加一个store对象的存储,它会把该对象添加到IndexedDB的store对象中,添加完成以后,我们会调用renderHTMLFunc() 这个方法来渲染我们的HTML页面,并且之后我们会发起一个AJAX请求。如果我们的网络一直是可以用的话,那么我们就不需要做任何处理 *** 作,但是如果我们的网络连接失败的情况下,我们调用了 addStore 方法,那么我们新的数据会被添加到indexedDB中,并且会调用renderHTMLFunc方法来渲染我们的页面,但是后面的AJAX请求就会调用失败。页面虽然更新了,indexedDB数据也保存到本地了,但是我们的服务器完全不知情,因此在这种情况下,我们需要使用service worker中的sync事件来解决这个问题。

我们要完成如下步骤:

1)在addStore函数添加代码,检查浏览器是否支持后台同步。如果支持,则注册一个 sync-store 同步事件,否则的话,便使用长规的AJAX调用。

2)在store.Js 中,添加到indexedDB代码,需要把状态改为 sending(发送中),在发送请求到服务器之前,这就是用户看到的状态, *** 作成功后,服务器会返回新的状态。

3)我们会向service worker添加一个事件监听器,用来监听sync事件,如果我们检测到sync的事件名称是 sync-store,事件监听器就会遍历每一个处于 sending 状态的预订,并且尝试发送给服务器。成功添加到服务器之后,indexedDB中的状态就会被修改成为新的状态,如果任何服务器请求失败的话,那么整个sync事件就会被拒绝,浏览器就会尝试在随后再运行这个事件了。

因此我们现在的第一步是在 addStore函数中,添加浏览器是否支持同步功能,如果支持的话,就会注册一个sync事件。如下代码(在myAccount.Js 代码修改):

var addStore = function(ID,age) {  var obj = {    ID: ID,age: age  };  addToObjectStore("store",obj);  renderHTMLFunc(obj);  // 先判断浏览器支付支持sync事件  if ("serviceWorker" in navigator && "SyncManager" in window) {    navigator.serviceWorker.ready.then(function(registration) {      registration.sync.register("sync-store")    });  } else {    $.getJsON("http://localhost:8081/public/Json/index.Json",function(data) {      updatedisplay(data);    });  }};

因此我们的 public/Js/myAccount.Js 所有的代码如下:

import $ from ‘jquery‘;$(function() {  function renderHTMLFunc(obj) {    console.log(obj);  }  function updatedisplay(d) {    console.log(d);  };  var addStore = function(ID,obj);    renderHTMLFunc(obj);    // 先判断浏览器支付支持sync事件    if ("serviceWorker" in navigator && "SyncManager" in window) {      navigator.serviceWorker.ready.then(function(registration) {        registration.sync.register("sync-store").then(function() {          console.log("后台同步已触发");        }).catch(function(err){          console.log(‘后台同步触发失败‘,err);        })      });    } else {      $.getJsON("http://localhost:8081/public/Json/index.Json",function(data) {        updatedisplay(data);      });    }  };  $("#submit").click(function(e) {    addStore(3,data);      updatedisplay(data);    });  });});

2)其次我们需要在 public/Js/store.Js 中openDataBase方法中的 result.onupgradeneeded 函数代码改成如下(当然要触发该函数,我们需要升级我们的版本号,即把 var DB_VERSION = 2; 把之前的 DB_VERSION 值为1 改成2):

var DB_VERSION = 2;var DB_name = ‘store-data2‘;// 监听当前版本号被升级的时候触发该函数result.onupgradeneeded = function(event) {  var db = event.target.result;  var upgradeTransaction = event.target.transaction;  var reservationsstore;  /*   是否包含该对象仓库名(或叫表名)。如果不包含就创建一个。   该对象中的 keyPath属性ID为主键  */  if (!db.objectStorenames.contains(‘store‘)) {    reservationsstore = db.createObjectStore("store",{ keyPath: "ID",autoIncrement: true });  } else {    reservationsstore = upgradeTransaction.objectStore("store");  }  if (!reservationsstore.indexnames.contains("IDx_status")) {    reservationsstore.createIndex("IDx_status","status",{unique: false});  }}

如上代码,我们在创建 store对象之前,我们会先判断该对象是否存在,如果不存在的话,我们会创建该对象,否则的话,我们就通过调用 event.target.transaction.objectStore("store")将获得更新事件中的事务,并且从事务中获取store对象存储的引用。

最后我们确认我们的store对象存储是否已经有 IDx_status 这个,如果不存在的话,如果不存在的话,我们就创建该索引。

3)现在我们需要修改我们的 public/Js/store.Js 中的getStore函数了,我们在该函数内部使用这个新的索引,就可以获取到该某个请求中的某个状态了,因此我们要对 我们的 getStore函数进行修改,让其支持接收两个可选的参数,索引名称,以及传递给该索引的值。如下代码的修改:

var getStore = function (indexname,indexValue) {  return new Promise(function(resolve,reject) {    openDataBase().then(function(db) {      var objectStore = openObjectStore(db,‘store‘);      var datas = [];      var cursor;      if (indexname && indexValue) {        cursor = objectStore.index(indexname).openCursor(indexValue);      } else {        cursor = objectStore.openCursor();      }      cursor.onsuccess = function(event) {        var cursor = event.target.result;        if (cursor) {          datas.push(cursor.value);          cursor.continue();        } else {          if (datas.length > 0) {            resolve(datas);          } else {            getDataFromServer().then(function(d) {              openDataBase().then(function(db) {                var objectStore = openObjectStore(db,"store","reaDWrite");                for (let i = 0; i < datas.length; i++) {                  objectStore.add(datas[i]);                }                resolve(datas);              });            });          }        }      }    }).catch(function() {      getDataFromServer().then(function(datas) {        resolve(datas);      });    });  });};

如上代码,我们对getStore函数接受了两个可选的新参数(indexname和indexValue)。其次,如果我们的函数接收了这些参数的话,就使用参数在特定的索引(indexname)上打开流标,然后打开特定值(indexValue)的流标,会把结果限定在指定的范围内。如果没有传递这些参数的话,它会向以前那样运行。

做出这两个地方的修改,我们的函数可以返回所有的结果,也可以返回结果中的一个子集,如下代码所示:

getStore().then(function(reservations){  // reservations 包含了所有的数据});getStore("IDx_status","Sending").then(function() {  // reservations 变量仅仅包含了状态为 "Sending" 的数据});

4)现在我们需要在我们的 sw.Js 中添加后台同步的事件监听器到 service worker中了。

首先我们在我们的sw.Js中引入 store.Js ,代码如下所示:

importScripts("/public/Js/store.Js");

然后在我们sw.Js的底部,添加如下代码:

var createStoreUrl = function(storeDetails) {  var storeUrl = new URL("http://localhost:8081/public/Json/index.Json");  Object.keys(storeDetails).forEach(function(key) {    storeUrl.searchParams.append(key,storeDetails[key]);  });  return storeUrl;};var syncStores = function() {  return getStore("IDx_status","Sending").then(function(reservations) {    return Promise.all(      reservations.map(function(reservation){        var reservationUrl = createStoreUrl(reservation);        return fetch(reservationUrl);      })    )  });};self.addEventListener("sync",function(event) {  if (event.tag === "sync-store") {    event.waitUntil(syncStores());  }});

如上代码,我们使用 self.addEventListener 为sync事件添加一个新的事件监听器,这个事件监听器会响应事件名称为 "sync-store" 的事件,然后使用 waitUntil方法等待 syncStores()函数返回的promise,会根据该promise的完成或拒绝来判断sync事件是完成还是拒绝,如果是完成的话,那么 sync-store的sync事件就会从SyncManager中删除,如果promise是拒绝的话,那么我们的SyncManager会保持 sync事件的注册,并且在随后会再次触发该事件。

syncStores() 会遍历IndexedDB中每一个标记为"Sending" 状态的数据,尝试会再次发送到服务器,并且返回一个promise,只有当promise发送成功了的话,那么就会完成状态。

然后在我们的getStore函数中,可以获取所有处于 Sending 状态的数据,该函数也返回了一个promise对象,该promise会决定整个syncStores函数的结果。要实现这点,我们使用了Promise.all()传入了一个promise数组,我们拿到该数据对象数组后,会通过Array.map()方法将数组的元素转化为 promise,我们使用 map对每个元素进行迭代,创建一个fetch请求发送到服务器来创建这个请求,fetch也会返回一个promise。

createStoreUrl 函数使用URL接口创建了一个新的URL对象,这个对象表示的是fetch请求接口,使用这种方式更优雅的创建带有查询字符串的URL,比如如下代码会打印带参数的url。

console.log(createStoreUrl({‘name‘: ‘kongzhi‘,‘age‘: 30}));

那么打印的 结构就是:http://localhost:8081/public/Json/index.Json?name=kongzhi&age=30; 这样的了。

完成上面的代码后,我们来打开我们的应用 http://localhost:8081/ 刷新下,然后我们把我们的网络断开,然后再点击 "点击我新增"这个文字,就会在控制台上打印如下信息了;如下图所示:

然后我们打开我们的网络,没过一会儿,就可以看到我们的请求会自动请求一次,如下图所示:

请求成功后,我们就可以把页面的消息 "请求加载中,请稍后..." 这几个字 可以改成 "请求成功了..." 这样的提示了。

如上代码后,当我们的网络恢复完成后,我们会重新发AJAX请求,请求完成后,可能会有新的请求状态数据,因此我们现在最后一步是需要更新我们的indexedDB数据库了,以便显示最新的消息给我们的用户,并且我们要更新我们的数据状态,等我们下一次 sync-store 事件注册的时候,不会重新发送。因此我们需要改变syncStores函数代码:

在更新之前,我们之前的代码是如下这样的:

var syncStores = function() {  return getStore("IDx_status","Sending").then(function(reservations) {    console.log(reservations);    return Promise.all(      reservations.map(function(reservation){        var reservationUrl = createStoreUrl(reservation);        return fetch(reservationUrl);      })    )  });};

更新之后的代码如下所示:

var syncStores = function() {  return getStore("IDx_status","Sending").then(function(reservations) {    console.log(reservations);    return Promise.all(      reservations.map(function(reservation){        var reservationUrl = createStoreUrl(reservation);        return fetch(reservationUrl).then(function(response) {          return response.Json();        }).then(function(newResponse) {          return updateInObjectStore("store",newResponse);        })      })    )  });};

github源码查看

总结

以上是内存溢出为你收集整理的渐进式web应用开发-- 使用后台同步保证离线功能(六)全部内容,希望文章能够帮你解决渐进式web应用开发-- 使用后台同步保证离线功能(六)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1051736.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)

保存