Service Worker本质上充当Web应用程序与浏览器之间的代理服务器,也可以在网络可用时作为浏览器和网络间的代理。它们旨在(除其他之外)使得能够创建有效的离线体验,拦截网络请求并基于网络是否可用以及更新的资源是否驻留在服务器上来采取适当的动作。他们还允许访问推送通知和后台同步API。
Service Worker的本质是一个Web Worker,它独立于JavaScript主线程,因此它不能直接访问DOM,也不能直接访问window对象,但是,Service Worker可以访问navigator对象,也可以通过消息传递的方式(postMessage)与JavaScript主线程进行通信。
Service Worker是一个网络代理,它可以控制Web页面的所有网络请求。
Service Worker具有自身的生命周期,使用好Service Worker的关键是灵活控制其生命周期。
Service Worker的作用
用于浏览器缓存
实现离线Web APP
消息推送
Service Worker兼容性
Service Worker是现代浏览器的一个高级特性,它依赖于fetch API、Cache Storage、Promise等,其中,Cache提供了Request / Response对象对的存储机制,Cache Storage存储多个Cache。
什么是
Service Worker
Service Worker
本质上充当Web应用程序与浏览器之间的代理服务器,也可以在网络可用时作为浏览器和网络间的代理。它们旨在(除其他之外)使得能够创建有效的离线体验,拦截网络请求并基于网络是否可用以及更新的资源是否驻留在服务器上来采取适当的动作。他们还允许访问推送通知和后台同步API
。Service Worker
的本质是一个Web Worker
,它独立于JavaScript
主线程,因此它不能直接访问DOM
,也不能直接访问window
对象,但是,Service Worker
可以访问navigator
对象,也可以通过消息传递的方式(postMessage)与JavaScript
主线程进行通信。Service Worker
是一个网络代理,它可以控制Web
页面的所有网络请求。Service Worker
具有自身的生命周期,使用好Service Worker
的关键是灵活控制其生命周期。Service Worker
的作用Web APP
Service Worker
兼容性Service Worker
是现代浏览器的一个高级特性,它依赖于fetch API
、Cache Storage
、Promise
等,其中,Cache
提供了Request / Response
对象对的存储机制,Cache Storage
存储多个Cache
。示例
在了解
Service Worker
的原理之前,先来看一段Service Worker
的示例:下面开始逐段逐段地分析,揭开
Service Worker
的神秘面纱:polyfill
首先看第一行:
self.importScripts('./serviceworker-cache-polyfill.js');
,这里引入了Cache API的一个polyfill,这个polyfill
支持使得在较低版本的浏览器下也可以使用Cache Storage API
。想要实现Service Worker
的功能,一般都需要搭配Cache API
代理网络请求到缓存中。在
Service Worker
线程中,使用importScripts
引入polyfill
脚本,目的是对低版本浏览器的兼容。Cache Resources List
AndCache Name
之后,使用一个
urlsToCache
列表来声明需要缓存的静态资源,再使用一个变量CACHE_NAME
来确定当前缓存的Cache Storage Name
,这里可以理解成Cache Storage
是一个DB
,而CACHE_NAME
则是DB
名:Lifecycle
Service Worker
独立于浏览器JavaScript
主线程,有它自己独立的生命周期。如果需要在网站上安装
Service Worker
,则需要在JavaScript
主线程中使用以下代码引入Service Worker
。此处,一定要注意
sw.js
文件的路径,在我的示例中,处于当前域根目录下,这意味着,Service Worker
和网站是同源的,可以为当前网站的所有请求做代理,如果Service Worker
被注册到/imaging/sw.js
下,那只能代理/imaging
下的网络请求。可以使用
Chrome
控制台,查看当前页面的Service Worker
情况:安装完成后,
Service Worker
会经历以下生命周期:download
)install
)activate
)用户首次访问
Service Worker
控制的网站或页面时,Service Worker
会立刻被下载。之后至少每24
小时它会被下载一次。它可能被更频繁地下载,不过每24
小时一定会被下载一次,以避免不良脚本长时间生效。在下载完成后,开始安装
Service Worker
,在安装阶段,通常需要缓存一些我们预先声明的静态资源,在我们的示例中,通过urlsToCache
预先声明。在安装完成后,会开始进行激活,浏览器会尝试下载
Service Worker
脚本文件,下载成功后,会与前一次已缓存的Service Worker
脚本文件做对比,如果与前一次的Service Worker
脚本文件不同,证明Service Worker
已经更新,会触发activate
事件。完成激活。如图所示,为
Service Worker
大致的生命周期:install
在安装完成后,尝试缓存一些静态资源:
首先,
self.skipWaiting()
执行,告知浏览器直接跳过等待阶段,淘汰过期的sw.js
的Service Worker
脚本,直接开始尝试激活新的Service Worker
。然后使用
caches.open
打开一个Cache
,打开后,通过cache.addAll
尝试缓存我们预先声明的静态文件。监听
fetch
,代理网络请求页面的所有网络请求,都会通过
Service Worker
的fetch
事件触发,Service Worker
通过caches.match
尝试从Cache
中查找缓存,缓存如果命中,则直接返回缓存中的response
,否则,创建一个真实的网络请求。如果我们需要在请求过程中,再向
Cache Storage
中添加新的缓存,可以通过cache.put
方法添加,看以下例子:activate
Service Worker
总有需要更新的一天,随着版本迭代,某一天,我们需要把新版本的功能发布上线,此时需要淘汰掉旧的缓存,旧的Service Worker
和Cache Storage
如何淘汰呢?Cache
是不被淘汰的。caches.keys()
拿到所有的Cache Storage
,把不在白名单中的Cache
淘汰。caches.delete()
方法。它接收cacheName
作为参数,删除该cacheName
所有缓存。sw-precache-webpack-plugin
sw-precache-webpack-plugin是一个
webpack plugin
,可以通过配置的方式在webpack
打包时生成我们想要的sw.js
的Service Worker
脚本。一个最简单的配置如下:
在执行
webpack
打包后,会生成一个名为service-worker.js
文件,用于缓存webpack
打包后的静态文件。一个最简单的示例。
Service Worker Cache
VSHttp Cache
对比起
Http Header
缓存,Service Worker
配合Cache Storage
也有自己的优势:Service Worker
可以立马使用缓存返回,但与此同时可以发起请求,校验是否有新版本更新。hash
值实在是太难看了。Http
缓存容易被冲掉,也容易过期,而Cache Storage
则不容易被冲掉。也没有过期时间的说法。Service Worker
可以实现离线访问应用。但是缺点是,由于
Service Worker
依赖于fetch API
、依赖于Promise
、Cache Storage
等,兼容性不太好。后话
本文只是简单总结了
Service Worker
的基本使用和使用Service Worker
做客户端缓存的简单方式,然而,Service Worker
的作用远不止于此,例如:借助Service Worker
做离线应用、用于做网络应用的推送(可参考push-notifications)等。甚至可以借助
Service Worker
,对接口进行缓存,在我所在的项目中,其实并不会做的这么复杂。不过做接口缓存的好处是支持离线访问,对离线状态下也能正常访问我们的Web
应用。Cache Storage
和Service Worker
总是分不开的。Service Worker
的最佳用法其实就是配合Cache Storage
做离线缓存。借助于Service Worker
,可以轻松实现对网络请求的控制,对于不同的网络请求,采取不同的策略。例如对于Cache
的策略,其实也是存在多种情况。例如可以优先使用网络请求,在网络请求失败时再使用缓存、亦可以同时使用缓存和网络请求,一方面检查请求,一方面有检查缓存,然后看两个谁快,就用谁。