在前一课咱们讲过,经过在服务端设置http请求头字段的方式,控制浏览器的静态资源缓存规则 那么,做为前端开发,有没有不须要后端配合的缓存方式呢? 下面,咱们就一块儿来了解一下,在客户端代码控制web离线缓存的sevice worker。javascript
Service Worker 是 Chrome 团队提出和力推的一个 WEB API,用于给 web 应用提供高级的可持续的后台处理能力。 该 WEB API 标准起草于 2013 年,于 2014 年归入 W3C WEB 标准草案,当前还在草案阶段。css
Service workers 本质上充当Web应用程序与浏览器之间的代理服务器,也能够在网络可用时做为浏览器和网络间的代理。 它们可以建立有效的离线体验,拦截网络请求并基于网络是否可用以及更新的资源是否驻留在服务器上来采起适当的动做。 他们还容许访问推送通知和后台同步API。前端
当浏览器发送请求时,首先到达sw脚本中,若是没有命中,再转发给http请求。java
sevice worker浏览器支持状况 web
注册 -> 安装 -> 激活 -> 废弃chrome
也能够在开发者工具中查看浏览器中sevice worker的状况 后端
f ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('sw.js', {scope: '/'})
.then(registration => {
console.log('ServiceWorker 注册成功!做用域为: ', registration.scope)
})
.catch(err => {
console.log('ServiceWorker 注册失败: ', err)
});
}
复制代码
代码解析:promise
// 安装阶段跳过等待,直接进入 active
self.addEventListener('install', function(event) {
event.waitUntil(self.skipWaiting());
});
复制代码
在下面的示例中,咱们实现对旧版本的缓存资源清理浏览器
this.addEventListener('activate', event => {
const cacheWhitelist = ['lzwme_cache_v1.6.0'];
event.waitUntil(
// 遍历当前的缓存,删除 指定版本号 以外的全部缓存
caches.keys().then(keyList => {
return Promise.all(keyList.map(key => {
if (cacheWhitelist.indexOf(key) === -1) {
return caches.delete(key);
}
}));
})
);
});
复制代码
传给 waitUntil() 的 Promise 会阻塞其余的事件,直到它完成。这能够确保清理操做会在第一次 fetch 事件以前完成缓存
参考下面的示例:
self.addEventListener('fetch', function(event) {
// console.log('Handling fetch event for', event.request.url);
event.respondWith(
// Opens Cache objects that start with 'font'.
caches.open(CURRENT_CACHES['carry']).then(function(cache) {
return cache.match(event.request).then(function(response) {
// 若是命中了缓存,直接返回缓存中的数据
if (response) {
console.log(' Found response in cache:', response);
return response;
}
// 请求是stream,只能使用一次
var fetchRequest = event.request.clone();
return fetch(fetchRequest)
.then(function(response) {
//请求不成功,则不存入缓存
if(!response || response.status !== 200) {
return response;
}
// 若是没有命中缓存,将请求和响应缓存到cache中
// 响应也是stream,只能使用一次,一次用于缓存,一次用于浏览器响应
var responseToCache = response.clone();
caches.open(CURRENT_CACHES['carry'])
.then(function(cache) {
// 抓取请求及其响应,并将其添加到给定的cache
cache.put(event.request, responseToCache);
});
return response;
});
}).catch(function(error) {
// Handles exceptions that arise from match() or fetch().
console.error(' Error in fetch handler:', error);
throw error;
});
})
);
});
复制代码
如下完整代码
var CACHE_VERSION = 2;
// Shorthand identifier mapped to specific versioned cache.
var CURRENT_CACHES = {
carry: 'version' + CACHE_VERSION
};
const cacheList = [
'css',
'js'
]
// 安装阶段跳过等待,直接进入 active
self.addEventListener('install', function(event) {
event.waitUntil(self.skipWaiting());
});
self.addEventListener('activate', function(event) {
var expectedCacheNames = Object.keys(CURRENT_CACHES).map(function(key) {
return CURRENT_CACHES[key];
});
// Active worker won't be treated as activated until promise resolves successfully.
event.waitUntil(
caches.keys().then(function(cacheNames) {
return Promise.all(
// 更新客户端
clients.claim(),
// 清理旧版本
cacheNames.map(function(cacheName) {
if (expectedCacheNames.indexOf(cacheName) == -1) {
console.log('Deleting out of date cache:', cacheName);
return caches.delete(cacheName);
}
})
);
})
);
});
self.addEventListener('fetch', function(event) {
console.log('Handling fetch event for', event.request.url);
let cached = cacheList.find(c => {return event.request.url.indexOf(c) !== -1 });
event.respondWith(
if(cached){
// 打开指定版本的缓存列表
// 每一个cache对象和请求的request url 匹配
caches.open(CURRENT_CACHES['carry']).then(function(cache) {
return cache.match(event.request).then(function(response) {
// 若是命中了缓存,直接返回缓存中的数据
if (response) {
console.log(' Found response in cache:', response);
return response;
}
// 请求是stream,只能使用一次
var fetchRequest = event.request.clone();
return fetch(fetchRequest)
.then(function(response) {
if(!response || response.status !== 200) {
return response;
}
// 若是没有命中缓存,将请求和响应缓存到cache中
// 响应也是stream,只能使用一次,一次用于缓存,一次用于浏览器响应
var responseToCache = response.clone();
caches.open(CURRENT_CACHES['carry'])
.then(function(cache) {
// 抓取请求及其响应,并将其添加到给定的cache
cache.put(event.request, responseToCache);
});
return response;
});
}).catch(function(error) {
// Handles exceptions that arise from match() or fetch().
console.error(' Error in fetch handler:', error);
throw error;
});
})
}else{
return fetch(fetchRequest)
.then(response => {
return response;
})
}
);
});
复制代码
致使废弃的缘由
sevice worker的做用,远远不止请求资源缓存这一条,基于 Service Worker API 的特性,结合 Fetch API、Cache API、Push API、postMessage API 和 Notification API,能够在基于浏览器的 web 应用中实现 如离线缓存、消息推送、静默更新等 native 应用常见的功能,以给 web 应用提供更好更丰富的使用体验。