Service Worker

  目录

Service Worker初探

简述

service worker定义先不谈,主要简单的介绍下笔者对service worker流程理解,也就是生命周期,直奔主题。

1.第一次进入html文件时,注册service worker文件(sw.js),接下来sw.js文件中的install事件响应,紧接着activate事件响应,最后是register注册的Promise的then执行,记住,这时registration的状态是installed。在第一次打开网页时,install和activate事件都会执行,可以在install事件里做缓存配置处理,可以在activate事件里做删除无用的缓存处理。
2.再次进入这个页面时,因为第一次已经注册了sw.js文件,所以install和activate事件是不会执行的,但是fetch事件可以执行,也可以理解为,再次进入这个页面时,service worker已经接管了这个页面,可以在fetch事件里对请求做处理,也就是service worker的核心功能所在。这时registration的状态是active。
3.service worker和html页面是分离的,页面关闭,service worker并不会关闭,每次打开html页面时,这个页面注册过的service worker都会对其进行监管操作,一个页面可以对应多个service worker,只有active状态下的service worker才是正在工作的。因为每次在修改了sw.js文件后,浏览器会自动检查这个文件是否有改变,如果有改变了,会执行步骤1的注册流程,这个时候可以在install事件中,加上self.skipWaiting(),它的作用是将当前的service worker状态提升到active,接管网页操作。

例子

sw.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./lib/1.js"></script>
<script src="./lib/2.js"></script>
<script src="./lib/3.js"></script>
<script src="./lib/4.js"></script>
<script src="./lib/5.js"></script>
<script src="./lib/6.js"></script>
</head>
<body>
<h1>service worker</h1>
<script>
if ('serviceWorker' in navigator) {
/* 当页面加载完成就创建一个serviceWorker */
window.addEventListener('load', function () {
/* 创建并指定对应的执行内容 */
/* scope 参数是可选的,可以用来指定你想让 service worker 控制的内容的子目录。 在这个例子里,我们指定了 '/',表示 根网域下的所有内容。这也是默认值。 */
navigator.serviceWorker.register('./sw.js', {scope: './'})
.then(function (registration) {
if (registration.installing) {
console.log('Service worker installing');
} else if (registration.waiting) {
console.log('Service worker installed');
} else if (registration.active) {
console.log('Service worker active');
}
})
.catch(function (err) {
console.log('ServiceWorker registration failed: ', err);
});
});
}
</script>
</body>
</html>

sw.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
var CACHE_NAME = 'v1';
/* 监听安装事件,install 事件一般是被用来设置你的浏览器的离线缓存逻辑 */
this.addEventListener('install', function (event) {
console.log('install-'+CACHE_NAME);
self.skipWaiting();
event.waitUntil(
/* 创建一个名叫V1的缓存版本 */
caches.open(CACHE_NAME).then(function (cache) {
/* 指定要缓存的内容,地址为相对于跟域名的访问路径 */
return cache.addAll([
'/sw.html',
'./lib/1.js',
'./lib/2.js',
'./lib/3.js',
]);
})
);
});
// 激活事件
this.addEventListener('activate', function(event) {
console.log('activate');
let cacheWhitelist = [CACHE_NAME];
// 将其他的chace缓存清除
event.waitUntil(
caches.keys().then (cacheNames => {
return Promise.all(
cacheNames.map( cacheName => {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName)
}
})
)
})
)
});
// fetch事件-是否是install时缓存的文件
// this.addEventListener('fetch', function(event) {
// event.respondWith(caches.match(event.request).then(function (response) {
// if (response) {
// console.log(response, '------');
// return response
// } else {
// console.log(event.request, '========');
// return fetch(event.request)
// }
// }));
// });
// fetch事件-
this.addEventListener('fetch', function(event) {
if (navigator.onLine) {
return fetch(event.request.clone()).then(function (response) {
if (!response || response.status !== 200) {
return response
}

caches.open(CACHE_NAME).then(function (cache) {
cache.put(event.request, response.clone())
})

return response
}).catch(function (err) {
console.log(err)
})
} else {
event.respondWith(caches.match(event.request).then(function (response) {
if (response) {
// A cached response has been found!
return response
} else {
// We don't have a cached response, initiate a fetch...
return fetch(event.request)
}
}))
}
});

总结

service worker功能非常强大,PWA就是基于service worker,以上只是简单的介绍,不过生命周期也就这么多内容。