PWA缓存控制和版本升级实践
PWA缓存控制和版本升级实践
PWA是会注册一个service-worker的,每次任何被 service worker 控制的资源被请求到时,都会触发 fetch 事件,这些资源包括了指定的 scope 内的文档,和这些文档内引用的其他任何资源(比如 index.html 发起了一个跨域的请求来嵌入一个图片,这个也会通过 service worker 。)
缓存
技术依据
我们可以给 service worker 添加一个 fetch 的事件监听器,接着调用 event 上的 respondWith()
方法来劫持我们的 HTTP 响应,然后你用可以用自己的方法来更新他们。
在任何情况下我们只是简单的响应这些缓存中的 url 和网络请求匹配的资源,比如下面的例子:
this.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
);
});
caches.match(event.request)
允许我们对网络请求的资源和 cache 里可获取的资源进行匹配,查看是否缓存中有相应的资源。这个匹配通过 url 和 vary header进行,就像正常的 http 请求一样,如果没有在缓存中找到匹配的资源,你可以告诉浏览器对着资源直接去 fetch 默认的网络请求。
fetch(event.request)
如果没有在缓存中找到匹配的资源,同时网络也不可用,你可以用 match()
把一些回退的页面作为响应来匹配这些资源。
caches.match('/fallback.html');
最佳实践
我们不仅仅可以在fetch的回调里面尝试从缓存中匹配资源,也可以将从网络请求的资源存储在缓存中。
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request).then(function(resp) {
return resp || fetch(event.request).then(function(response) {
return caches.open('v1').then(function(cache) {
cache.put(event.request, response.clone());
return response;
});
});
})
);
});
这里我们用 fetch(event.request)
返回了默认的网络请求,它返回了一个 promise 。当网络请求的 promise 成功的时候,我们 通过执行一个函数用 caches.open('v1')
来抓取我们的缓存,它也返回了一个 promise。当这个 promise 成功的时候, cache.put()
被用来把这些资源加入缓存中。资源是从 event.request 抓取的,它的响应会被response.clone()
克隆一份然后被加入缓存。这个克隆被放到缓存中,它的原始响应则会返回给浏览器来给调用它的页面。
我们之使用response.clone()
是因为请求和响应流只能被读取一次。为了给浏览器返回响应以及把它缓存起来,我们不得不克隆一份。所以原始的会返回给浏览器,克隆的会发送到缓存中。它们都是读取了一次。
我们还可以加上一个回退方案,以便在缓存中找不到并且网络不可用的时候有内容返回给用户
this.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request).then(function() {
return fetch(event.request).then(function(response) {
return caches.open('v1').then(function(cache) {
cache.put(event.request, response.clone());
return response;
});
});
}).catch(function() {
return caches.match('/sw-test/gallery/myLittleVader.jpg');
})
);
});
升级
如果你的 service worker 已经被安装,但是刷新页面时发现有一个新版本的可用,新版的 service worker 会在后台install
,但是还没active
。当不再有任何已加载的页面在使用旧版的 service worker 的时候,新版本才会激活。
更新service-worker
install
事件就派上用场了,我们可以改造下install
事件的回调。
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open('v2').then(function(cache) {
return cache.addAll([
'/sw-test/',
'/sw-test/index.html',
'/sw-test/style.css',
'/sw-test/app.js',
'/sw-test/image-list.js',
// ...
]);
})
);
});
当安装发生的时候,前一个版本依然在响应请求,新的版本正在后台安装,我们调用了一个新的缓存 v2,所以前一个 v1 版本的缓存不会被扰乱。
删除旧的缓存
这个时候activate
事件就派上用场了,当之前版本还在运行的时候,一般被用来做些会破坏它的事情,比如摆脱旧版的缓存。
传给 waitUntil()
的 promise 会阻塞其他的事件,直到它完成。所以你可以确保你的清理操作会在你的的第一次 fetch 事件之前会完成。
self.addEventListener('activate', function(event) {
var cacheWhitelist = ['v2'];
event.waitUntil(
caches.keys().then(function(keyList) {
return Promise.all(keyList.map(function(key) {
if (cacheWhitelist.indexOf(key) === -1) {
return caches.delete(key);
}
}));
})
);
});
版本升级小技巧
因为我们的版本号一般都是字符串形式,我们就需要让浏览器知道哪个是新版本了,比如v1.2
是新版本还是说v1.11
,从数值上看 2 < 11 ,但是很多系统一般是根据ASCII码进行排序的,这样就会让部分系统存在歧义了,我们应该从自己的角度上避免了。前叙述的例子改成v.1.02
和1.11
就消除了这种歧义。
一个简单的更新补丁版本的方法,大版本和小版本类似。
function updateVersion(version) {
const lastVersion = getCurrentVersion(version);
const [main, sub, fix] = lastVersion.split('.');
const fixNum = parseInt(fix) + 1 + '';
const newVersion = [main, sub, fixNum.padStart(4, '0')].join('.');
return [lastVersion, newVersion];
}
- 分类:
- Web前端
相关文章
微软针对windows7用户发布IE10
微软已经声明windows7用户终于可以享用IE10了,先前IE10是windows8用户独享的,但是去年11月份,微软公司WIIN7用户了一个ie10的预览版。但是从今天开始win7用户已经可以下载 阅读更多…
黑莓官方催促twitter用户用回老版本客户端
鉴于许多黑莓用户的抱怨,黑莓现在在自己的应用市场推送最新的twitter客户端更新。如果你想修复twitter客户端的140字问题,那么你可能得用下面的方式来解决了:那就是回滚到twitter的上个 阅读更多…
网站更新至wordpress3.3
刚升级,使用中... 阅读更多…
道招网终于完成改版了
这个清明节放假三天,由于疫情还没有完全退去,大家还不太适合大规模聚集,更重要的是我本来也爱宅着不动。放假前就决定这三天干点正事,于是就想起把之前立的flag扶一下,把道招网的vue服务端渲染版彻底上 阅读更多…
凡客联盟会员猛增,联盟实行收款账户信息升级
尊敬的凡客联盟会员: 随着联盟会员数量的不断增加,为加快联盟会员付款的进程、确保银行账户信息的安全性。我们将针对联盟用户的付款信息做相关升级,请联盟会员按照我们的提示规范自己的收款账户信息,以保 阅读更多…
wordpress博客提示“Briefly unavailable for scheduled maintenance. Check back in a minute”
所谓“Briefly unavailable for scheduled maintenance. Check back in a minute”翻译过来就是“正在执行例行维护,请一分钟后回来”,这 阅读更多…