共计 4691 个字符,预计需要花费 12 分钟才能阅读完成。
看了很多介绍 Service Worker 的,看得都挺模糊的,所以决定自己写一篇文件整理一下思路。
一、Service Worker API 名词区分
1、ServiceWorkerContainer:navigator.serviceWorker 返回的就是 Service WorkerContainer 对象,主要是用户在页面注册 serviceWorker,调用方法:
navigator.serviceWorker.register(scriptURL, options)
.then(function(ServiceWorkerRegistration) {…})
2、ServiceWokrerGlobalScope:主要是用户在 sw.js 文件的全局变量,即 this 的指向 3、ServiceWorkerRegistration:在页面调用 serviceWorker.register 注册返回一个 Promise 对象,当 resolve 时传递给 then 的函数参数就是 ServiceWorkerRegistration.4、ServiceWorker:表示 ServiceWorkerRegistration.installing || ServiceWorkerRegistration.waiting || ServiceWorkerRegistration.active
二、Service Worker 注册
1、index.html
<script>
// register
if(“serviceWorker” in navigator){
navigator.serviceWorker.register(‘./sw.js’)
.then(function(registration){
console.log(“Register success: “,registration.scope);
});
.catch(function(err){
console.log(“Register failed: “,err);
});
}else{
console.log(‘Service workers are not supported.’);
}
</script>
2、sw.js
var CACHE_NAME = ‘sw-test-v1’;
this.addEventListener(‘install’,function(event){
console.log(“installing…”);
event.waitUntil(caches.open(CACHE_NAME).then(function(cache){
cache.addAll([
‘images/resource01.jpg’,
‘images/resource02.jpg’,
….
]);
}));
});
this.addEventListener(‘fetch’, function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
if (response) {// 缓存命中,返回缓存
return response;
}
// 请求是 stream 数据,只能使用一次,所以需要拷贝,一次用于缓存,一次用于浏览器请求
var fetchRequest = event.request.clone();
return fetch(fetchRequest)
.then(function(response) {
if(!response || response.status !== 200) {
return response;
}
// 响应也是 stream,只能使用一次,一次用于缓存,一次用于浏览器响应
var responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(function(cache) {
cache.put(event.request, responseToCache);
});
return response;
});
})
);
});
sw.js 工作内容:首先监听 install 事件,调用 cache.addAll() 方法将静态资源加入缓存中。然后监听 fetch 事件,判断当前请求的 url 是否在缓存中,如果在则返回内容,如果不在,则向服务端发起请求数据,将返回的数据放入缓存中并且返回给浏览器。代码中的方法解析:1、caches.match():检查给定的 Request 对象或 url 字符串是否是一个已存储的 Response 对象的 key. 该方法针对 Response 返回一个 Promise,如果没有匹配则返回 undefined。cache 对象按创建顺序查询,等同于在每个缓存上调用 cache.match() 方法(按照 caches.keys() 返回的顺序 ) 直到返回 Response 对象。语法如下:
caches.match(request, options).then(function(response) {
// Do something with the response
});
参数解析:
options: 可选,配置对象中的属性控制在匹配操作中如何进行匹配选择,具体属性如下:
ignoreSearch: Boolean 值,指定匹配过程是否应该忽略 url 中查询参数,默认 false。
ignoreMethod: Boolean 值,当被设置为 true 时,将会阻止在匹配操作中对 Request 请求的 http 方式的验证 (通常只允许 GET 和 HEAD 两种请求方式)。该参数默认为 false.
ignoreVary: Boolean 值,当该字段被设置为 true, 告知在匹配操作中忽略对 VARY 头信息的匹配。换句话说,当请求 URL 匹配上,你将获取匹配的 Response 对象,无论请求的 VARY 头存在或者没有。该参数默认为 false.
cacheName: DOMString 值,表示所要搜索的缓存名称。
2、caches.open():返回一个 resolve 为匹配 cacheName 的 cache 对象的 Promise . 如果指定的 cache 不存在,则使用该 cacheName 创建一个新的 cache 并返回。
caches.open(cacheName).then(function(cache) {});
3、cache.addAll():将静态资源加入缓存中
cache.addAll(requests[]).then(function() {
// 已加入缓存
});
该方法会覆盖掉以前存储在缓存中的匹配的健值对,但是后面监听对 fetch 事件中调用 cache.put() 方法又会覆盖掉之前在 cache.addAll() 中添加到缓存中所匹配的健值对。4、cache.put():允许将键 / 值对添加到当前的 Cache 对象中. 它将覆盖先前存储在匹配请求的 cache 中的任何键 / 值对。注意: Cache.add/Cache.addAll 不会缓存 Response.status 值不在 200 范围内的响应,而 Cache.put 允许你存储任何请求 / 响应对。因此,Cache.add/Cache.addAll 不能用于不透明的响应,而 Cache.put 可以。
cache.put(request, response).then(function() {
// request/response pair has been added to the cache
});
5、event.waitUntil():扩展了事件的生命周期。在服务工作线程中,延长事件的寿命从而阻止浏览器在事件中的异步操作完成之前终止服务工作线程。在 install 事件中,它延迟将被安装的 worker 视为 installing,直到传递的 Promise 被成功地 resolve。主要用于确保:服务工作线程在所有依赖的核心 cache 被缓存之前都不会被安装。在 activate 事件中,它延迟将 active worker 视为已激活的,直到传递的 Promise 被成功地 resolve。这主要用于确保:任何功能事件不会被分派到 ServiceWorkerGlobalScope 对象,直到它升级数据库模式并删除过期的缓存条目。当该方法运行时,如果 Promise 是 resolved,任何事情都不会发生;如果 Promise 是 rejected,installing 或者 active worker 的 state 会被设置为 redundant。语法:event.waitUntil(promise)6、event.respondWith():阻止浏览器默认的 fetch 处理方法,允许用户自己提供一个 promise 对象作为 response 返回。
fetchEvent.respondWith(
// Promise that resolves to a Response.
)
Parameters:A Promise for a Response.
上面的 sw.js 只是一个最基本的 serviceWorker,在日常工作中,我们还需要考虑更新。
三、Service Worker 更新
(一)自动更新
this.addEventListener(‘install’,function(event){
this.skipWaiting();
});
this.addEventListener(‘activate’, function (event) {
this.clients.claim();
});
skipWaiting(): 强制等待中的 service worker 跳过等待成为激活的 service worker。虽然该方法在任何时候都是可以调用的,但是只有在新安装的 service worker 仍然处于等待状态时才会起作用;所以在 install 事件里面调用是非常常见的。与 clients.claim() 一起调用以确保更新当前的 client 和其他激活的 clients。clients.claim(): 允许一个激活的 service worker 将其设置为其他同 scope 下的 clients 的 controller。该方法会触发要被该 service worker 控制的其他任何 clients 的 navigator.serviceWorker 上的 ”controllerchange” 事件。当一个 service worker 初始注册时并不会使用该 service worker,直到下次加载页面时。该方法会让这些页面直接被控制,注意,这将导致你的 service worker 将控制定期加载的页面,也有可能控制其他 service worker 加载的页面。
(二)手动更新
手动更新主要是调用在 index.html 注册 serviceWorker 时的 registration 的 update() 方法:ServiceWorkerRegistration.update(); 它会获取 worker 的脚本 URL,如果新的 worker 与当前的 worker 并不是完全相同的(byte-by-byte identical)则安装新的 worker;如果前一次 worker 获取发生在 24 小时之前,则 worker 的获取将绕过任何浏览器缓存。
navigator.serviceWorker.register(‘./sw.js’).then(function(registration){
registration.update();
});
参考学习链接:https://developer.mozilla.org…https://segmentfault.com/a/11…