什么是ServiceWorker
ServiceWorker是一种特殊的WebWorker,是在主线程外的另一个独立的线程,通常用作大量计算任务的后台进程。
ServiceWorker于2014年5月由W3C草案定义,它的前身是Application Cache。
在页面请求中,ServiceWorker会根据条件选择使用缓存或者请求新的资源。
ServiceWorker特性
- 不能直接访问/操作 Dom
- 需要时直接唤醒,不要时自动休眠
- 离线缓存内容开发者可控
- 除非手动卸载,不然永远存活
- 必须在Https(除本地环境)下工作
- 大量使用了Promise
初识ServiceWorker
判断是否支持ServiceWorker
if ('serviceWorker' in navigator) { console.log('支持ServiceWorker'); } else { console.log('不支持ServiceWorker'); }
注册ServiceWorker
假设工作目录为:. ├─sw.js └test.html
window.addEventListener('load', function () { // 建议在load事件中执行,因为过早的执行会导致页面加载速度过慢 this.navigator.serviceWorker.register('sw.js', { scope: '/corss/' }) // 第一个参数为sw文件路径,第二个参数为配置对象(scope,type,updateViaCache) // scope:设置sw可调用文件的范围,默认为父级目录。此处意为只能调用https://::/corss/*下的文件。 .then(function (registration) { console.log("Service Worker注册成功!"); }) .catch(function (err) { console.log(err); }) })
- 请注意:Service Worker不能“越域”,但除下面的情况外。
如果注册的域在远程服务器返回的Service Worker允许工作的最大的域,注册也会成功。
- 只要注册的scope不一样,在同一域下允许注册多个不同的scope的service worker。
ServiceWorker安装(install)事件
在Service Worker注册成功后,在被注册的sw.js文件中,会存在全局变量self
和this
(它俩是同一个对象),可以通过self
或this
甚至不写来访问Service Worker对象。
假设工作目录为:
.
├─sw.js
├─test.html
└─test.css
└test.js
监听install
事件,并且缓存文件。
<!-- test.html -->
...
<body>
<script>
navigator.serviceWorker.register('sw.js');
</script>
</body>
...
// sw.js
addEventListener('install', function (event) {
event.waitUntil(
// waitUntil将会使程序视为已经安装完成,但会等待所有的缓存都完成后再真正安装。
// 这确保了程序可以在缓存完成之前就可以使用。
caches.open('sw-cache')
// 使用全局注册的caches开辟一个名为sw-cache的缓存空间
.then(function (cache) {
// 开辟成功,拿到名为cache的缓存空间
return cache.addAll([
'./',
'./test.js',
'./test.css',
]);
// 将需要缓存的资源添加到缓存空间
})
.catch(function (err) {
// 开辟失败
console.log(err);
})
);
});
缓存完毕后在浏览器应用程序->缓存存储->sw-cache(创建的缓存空间名)中会看到缓存的资源。
ServiceWorker激活(activate)事件
激活事件会在缓存完毕后触发,可以在激活事件中执行一些操作。
例如删除旧的缓存。
假设工作目录为:
.
├─sw.js
├─test.html
└─test.css
└test.js
监听install
事件,并且缓存文件。
<!-- test.html -->
...
<body>
<script>
navigator.serviceWorker.register('sw.js');
</script>
</body>
...
// sw.js
addEventListener('activate', function (event) {
event.waitUntil(Promise.all([
// 异步操作
clients.claim(),
// 由于service worker初始不会被调用,所以需要手动调用claim方法使其立即生效
caches.keys().then(function (keys) {
// 获取所有缓存空间名称
return Promise.all(keys.map(function (key) {
if (key !== 'sw-cache') {
// 如果缓存空间名称不是sw-cache,则删除
return caches.delete(key);
}
}));
}),
]))
})
以上代码会删除所有缓存空间名称不是sw-cache的缓存空间。