下面把学习的过程中遇到的问题和感悟记录如下:
我用的webstorm
一个页面,引入了index.js,index.js的代码如下:
navigator.serviceWorker
.register('./sw.js')
.then(function (reg) {
console.log('Service Worker Registered');
});
setTimeout(() => {
const img = new Image();
img.src = 'img/limochou.jpg';
document.body.appendChild(img);
}, 1000);
setTimeout(() => {
const img = new Image();
img.src = 'img/zhaomin.jpg';
document.body.appendChild(img);
}, 1000);
sw的代码如下:
let pre = '/your-first-pwapp-master/mytest/';
let toCaches = [
pre + 'index.html',
pre + 'index.js',
pre + 'img/zhaomin.jpg',
pre + 'img/xiaolongnv.jpg',
];
self.addEventListener('install', event => {
console.log('install');
event.waitUntil(
caches.open('one')
.then(cache => cache.addAll(toCaches)) //还可以有返回值啊,我都不知道
.then(ok => console.log('add all ok'), e => console.log(e))
);
});
self.addEventListener('activate', event => {
console.log('one now ready to handle fetches!');
});
self.addEventListener('fetch', event => {
console.log(`fetch`, event.request.url);
caches.keys().then(ks => console.log(ks));
if (event.request.url.includes('zhaomin')) {
event.respondWith(caches.match(pre + 'img/xiaolongnv.jpg'));
} else {
event.respondWith(
caches.match(event.request).then(function (response) {
if (response) {
console.log('有', event.request.url);
return response;
} else {
console.log('没有', event.request.url);
return fetch(event.request);
}
})
);
}
});
在我本地使用的是webstorm访问,
http://localhost:63342/your-first-pwapp-master/mytest/index.html?_ijt=u8bf0oqpq91pfok9oi8tv6id2
但是当我勾选了offline之后,不能访问了,但是我已经离线了啊,service worker应该是支持离线的啊,为什么呢,后来我找到原因了:
就是因为用webstorm打开的时候它默认带上了参数,把参数去掉就可以了:
http://localhost:63342/your-first-pwapp-master/mytest/index.html
到目前为止,看到的情况是这样子的:
1. 第一次打开链接会看到下面的页面:
2. 刷新页面会看到:
第一次打开看到李莫愁和赵敏,刷新之后用小龙女替换了赵敏。
想做到不关闭浏览器,也不关闭标签页面,通过刷新来更新
我先更新了index.js,加入了一句话:
alert('我更新了');
也修改了sw.js:
// caches.open('one')
caches.open('two')
还有:
self.addEventListener('activate', event => {
console.log('two now ready to handle fetches!');
});
http://localhost:63342/your-first-pwapp-master/mytest/index.html
继续刷新页面,发现不管刷新多少次都不会有alert,点击上图中的update,skipWaiting都不行,勾选了update on reload 也不行,直到我点击了unregister之后才可以,不过这个可以只有一次有效,再次刷新还是走的旧的,为什么会这样呢,我看了看cache storage里面的缓存:
可以看到这个时候two里面缓存的index.js还是旧的,和one里面的是一样的。那么如果想让新的代码起作用怎么办?
self.addEventListener('install', event => {
console.log('install');
event.waitUntil(
Promise.all([
// caches.open('one')
caches.open('two')
.then(cache => cache.addAll(toCaches)) //还可以有返回值啊,我都不知道
.then(ok => console.log('add all ok'), e => console.log(e))
,
// 清理旧版本
caches.keys().then(function (cacheList) {
return Promise.all(
cacheList.map(function (cacheName) {
if (cacheName !== 'two') {
console.log('清理',cacheName);
return caches.delete(cacheName);
}
})
);
})
])
);
});
然后刷新两次,第一次刷新变化如下:
从上图可以看出缓存one已经被清理了,但是新的sw还处于waiting状态,
第二次刷新之后,结果如下:
新的sw还没有activate,但是alert已经弹出来了!
我尝试点击skipWaiting,打印出来了:
two now ready to handle fetches!
这是不是说明新的sw即使没有activate,也能接管页面发出的请求,因为真正起作用的是缓存呢?
self.addEventListener('activate', event => {
console.log('two now ready to handle fetches!');
event.waitUntil(
Promise.all([
// 清理旧版本
caches.keys().then(function (cacheList) {
return Promise.all(
cacheList.map(function (cacheName) {
if (cacheName !== 'two') {
console.log('清理',cacheName);
return caches.delete(cacheName);
}
})
);
})
])
);
});
第一次刷新结果如下:
新的sw安装了,还没有activate
第二次刷新刷新还是旧的,得点击skipWaiting才能让新的sw activate,才能弹出alert。
为了不用点击skipWaiting,在install事件中加入:
self.skipWaiting();
这样的话第二次刷新就弹出alert了。
不过尝试1中的实现可以少写一行代码。。。
参考文献:
1. https://developers.google.com/web/fundamentals/primers/service-workers/lifecycle?hl=zh-cn#clientsclaim
2. https://mdn.mozillademos.org/files/12636/sw-lifecycle.png
3. https://lavas.baidu.com/pwa/offline-and-cache-loading/service-worker/how-to-use-service-worker#service-worker-%E7%89%88%E6%9C%AC%E6%9B%B4%E6%96%B0