Service Workder相当于浏览器与web应用程序之间的代理服务器,可以捕获请求事件并做相应处理;目前主要用于离线应用以及消息推送及后台同步等;
demo地址
注册 可以通过serviceWorker.register()方法注册一个Service Worker实例,它是由Promise实现的,resolve后在then函数中拿到registration对象;包含了所注册sw的相关信息,如下图:
具体注册实现的过程如下图:
if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('sw.js') .then(registration => { console.log('sw installed: ', registration); }) .catch(err => console.log('sw installed failed: ', err)) }) }安装 Service Worker 在本文生命周期一节中,根据图示我们看到install事件中可以通过event.waitUntil()方法建立一个Promise对象来等待安装完成,安装完成后则Promise被resolve,然后我们可以打开缓存并存缓存需要缓存的资源;
具体实现如下:
var CACHE_NAME = 'sw-cache'; var CACHE_URLS = ['./index.html', './index.js', './public/equal.png', './public/icon.png']; self.addEventListener('install', e => { e.waitUntil( caches.open(CACHE_NAME) // 打开缓存 .then(cache => cache.addAll(CACHE_URLS)) ) }捕获请求并处理
具体实现如下:
self.addEventListener('fetch', e => { e.respondWith( caches.match(e.request) // 检测缓存资源和请求资源是否匹配, e.request具有以下属性:url/method/header/body .then(res => { if (res) { return res; } console.log('loaded from sw'); }) ) })更新
自动更新 Service Workder的更新遵循以下步骤(来自谷歌开发者):
更新您的服务工作线程 JavaScript 文件。 用户导航至您的站点时,浏览器会尝试在后台重新下载定义 Service Worker 的脚本文件。 如果 Service Worker 文件与其当前所用文件存在字节差异,则将其视为新 Service Worker。新 Service Worker 将会启动,且将会触发 install 事件。此时,旧 Service Worker 仍控制着当前页面,因此新 Service Worker 将进入 waiting 状态。当网站上当前打开的页面关闭时,旧 Service Worker 将会被终止,新 Service Worker 将会取得控制权。新 Service Worker 取得控制权后,将会触发其 activate 事件。下图可以看到:当我们更新了sw.js文件后,新的sw处于waiting to active的状态,而旧的sw仍然运行并且处于active状态;
关闭上图中的标签页http://127.0.0.1:5500/service%20worker/index.html并重新打开页面后:如下图,我们可以看到新的id为128的sw已经运行并处于active状态; 当然,可以通过调用self.skipWaiting()跳过等待阶段,在安装完成后立即激活;
手动更新
navigator.serviceWorker.register('/sw.js').then(reg => { // something later reg.update(); })删除旧缓存 由于浏览器对Service Worker可用的磁盘空间有严格限制,因此更新Service Worker时,我们需要进行缓存管理; 根据Service Worker的生命周期,我们可以看到在active阶段Service Worker处于活跃状态,即可以管理旧sw相关的资源;
self.addEventListener('activate', function(event) { // 建立需要保存的缓存白名单 var cacheWhitelist = ['pages-cache-v1', 'blog-posts-cache-v1']; event.waitUntil( caches.keys().then(function(cacheNames) { return Promise.all( cacheNames.map(function(cacheName) { if (cacheWhitelist.indexOf(cacheName) === -1) { return caches.delete(cacheName); } }) ); }) ); });