介绍
Service Workder相当于浏览器与web应用程序之间的代理服务器,可以捕获请求事件并做相应处理;目前主要用于离线应用以及消息推送及后台同步等;
特性
- 无法直接访问和操作DOM
- 在长时间不用时会被中止并在下次需要时重启;
- 可以访问和操作
indexedDB API
- 推荐使用HTTPS
- 内部实现基于
Promise
生命周期
install
事件是SW的第一个事件,只会发生一次,使用e.waitUtil()
监测是否安装成功;- 生命周期中的主要围绕两个事件
install
和activate
:install
前后的生命周期包括installing
和installed
,activate
前后的生命周期包括activating
和activated
;最后SW不用或者新旧更替时经历的生命周期时redundant
; - 在安装成功并处于
活动状态
之前,不会处理functional events
; - 处于
activated
状态才可以处理functional events: fetch/push/sync
;
支持的事件
使用
-
注册
可以通过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); } }) ); }) ); });