什么是Service Worker
Service worker是一个注册在指定源和路径下的事件驱动worker。它采用JavaScript控制关联的页面或者网站,拦截并修改访问和资源请求,细粒度地缓存资源。Service Worker 可以使你的应用先访问本地缓存资源,包括js、css、png、json等多种静态资源。
Service Worker的特点
- 独立于主JavaScript线程(这就意味着它的运行丝毫不会影响我们主进程的加载性能)
- 设计完全异步,大量使用Promise(因为通常Service Worker通常会等待响应后继续,Promise再合适不过了)
- 不能访问DOM,不能使用XHR和localStorage
- Service Worker只能由HTTPS承载(出于安全考虑)
Service Worker用法
注册
使用 ServiceWorkerContainer.register() 方法注册service worker。
// sw.js
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/loading-page-sw.js', {scope: '/'}).then(function(reg) {
// reg可以查看当前sw的状态和作用域等
}).catch(function(error) {
// registration failed
console.log('Registration failed with ' + error);
});
}
缓存处理
- caches.open(SW_VERSION):打开缓存, SW_VERSION: 版本
- cache.addAll(CACHE_FILE_LIST):添加缓存, CACHE_FILE_LIST:文件路径列表
- caches.keys():获取本地存储的版本集合
- caches.delete(key): 删除某个版本的缓存信息
- cache.put(event.request, responseClone):手动添加缓存,参数为request,response
下面附完整代码
// loading-page-sw.js
const SW_VERSION = 'V1';
const CACHE_FILE_TYPE = [ 'js','css', 'html','jpg','json','png''mp3','wav','mp4','ttf'];
//需要确认缓存的文件
const CACHE_FILE_LIST = [];
// 需要忽悠的文件列表
const IGNORE_FILE_LIST = [
'/test/index.js',
];
/**
* 是否是对应的文件类型
* @param {*} url
*/
function isAcceptFile(url) {
var r = new RegExp("\\.(" + CACHE_FILE_TYPE.join('|') + ")$");
return r.test(url);
}
/**
* 检查文件名
*/
function checkIgnoreFileName(url) {
var r = new RegExp("(" + IGNORE_FILE_LIST.join('|') + ")$");
return r.test(url);
}
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(SW_VERSION).then(function(cache) {
return cache.addAll(CACHE_FILE_LIST);
})
);
});
self.addEventListener('activate', function(event) {
var cacheWhitelist = [SW_VERSION];
event.waitUntil(
caches.keys().then(function(keyList) {
return Promise.all(keyList.map(function(key) {
if (cacheWhitelist.indexOf(key) === -1) {
return caches.delete(key);
}
}));
})
);
});
// 监听浏览器的所有fetch请求,对已缓存的资源使用本地缓存回复
self.addEventListener('fetch', function(event) {
const {method, url} = event.request;
event.respondWith(
caches.match(event.request).then(function(response) {
if (response !== undefined) {
return response;
} else {
return fetch(event.request).then(function (response) {
let responseClone = response.clone();
if (method === 'POST') {
return response
}
if (!isAcceptFile(url)) {
return response
}
if (checkIgnoreFileName(url)) {
return response
}
caches.open(SW_VERSION).then(function (cache) {
cache.put(event.request, responseClone);
});
return response;
}).catch(function (error) {
return Promise.reject(error);
});
}
})
);
});
service worker调试检查
查看service worker进程状态
service worker实际上提供的是本地缓存服务,所以和我们平时查看localStorage差不多,打开谷歌浏览器调试中心,在Application栏下,就能看到Service Woerkers,
可通过右侧Unregister来注销service worker进程。
查看本地存储信息
service worker会根据我们的版本在本地存储相应版本的文件,如图:
V1: 是我们自定义的版本号
缓存的文件已列表的形式被列出,信息有名称、返回类型、上下文长度、缓存时间等。
HTTP缓存
当我们的页面发起资源请求时,浏览器会通过缓存等手段来尽快响应,避免不必要的http消耗,所以我们经常见到:Memory Cache、Disk Cache、Push Cache,现在又多了一种ServiceWorker。我们来简单对比如下:
ServiceWorker
当我们启用ServiceWorker时,浏览器就会显示我们的资源来自ServiceWorker。Service Worker的缓存有别与其他缓存机制,我们可以自由控制缓存、文件匹配、读取缓存,并且是持续性的。当ServiceWorker没有命中时才会去重新请求数据。
Memory Cache
Memory Cache为内存中的缓存,读取内存中的资源是非常快的。 是浏览器为了加快读取缓存速度而进行的自身的优化行为,不受开发者控制,也不受 HTTP 协议头的约束。内存读取虽然快且高效,但它是短暂的,当浏览器或者tab页面关闭,内存就会被释放了。而且内存占用过多会导致浏览器占用计算机过大内存。
Disk Cache
Disk Cache 将资源存储在硬盘中,读取速度次于Memory Cache。
优点:可长期存储,可定义时效时间、容量大;缺点:读取速度慢。
根据http header 请求头触发的缓存策略来做缓存,包含强缓存和协商缓存。
Push Cache
当以上三种缓存都没有命中时才会使用Push Cache。它只在会话(Session)中存在,一旦会话结束就被释放,并且缓存时间也很短暂。这种缓存一般用不到。
我们通过控制台network,最直观的查看资源用的缓存方式。如图所示:
Service Worker注销和删除
我们对Service Worker已经做了用法说明,并和其他缓存做了对比;最后我们来说说如何注销Service Worker和删除本地缓存吧!
注销
通过调用unregister()函数来注销,代码如下:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.getRegistrations()
.then(function(registrations){
registrations.forEach(function(registration) {
registration.unregister();
})
})
}
删除
通过调用caches.delete()删除对,代码如下:
if (window.caches && caches.keys) {
caches.keys().then(function(keys) {
keys.forEach(function(key) {
caches.delete(key)
})
})
}
写在最后
由于Service Worker是单独运行环境,独立于主JavaScript进程的,导致前端获取的navigator.userAgent和后台获取的userAgent不一样,若在项目中需要使用Service worker时需观察自身业务是否有影响,多做测试观察。
本文固定连接:https://code.zuifengyun.com/2022/10/3160.html,转载须征得作者授权。