前言
本文记录在angular5的项目中添加serviceWorker时遇到问题以及代码解析。
文章提纲:
- serviceWorker介绍
- 如何在angular5项目中添加serviceWorker
- serviceWorker代码解析
- 遇到的问题
serviceWorker是什么?
serviceWorker是浏览器在后台独立于网页运行的一段脚本。他通过域名标识不同的网页。网页通过注册自己的serviceWorker,可以将一些相对独立的任务丢到serviceWorker里面运行,并最终通过postMessage进行通信。
1)生命周期
一个serviceWorker的的生命周期经历四个步骤:installing,installed,activating,activated,redundant。
installing:标志着安装的开始,在这个过程中设置离线缓存的config。
installed:已经安装完毕,等待其他的service worker线程关闭。
activated:激活态,表明该service worker开始正式工作。
activating:如果ngsw-worker.js执行出现了错误,则会进入激活失败的状态。
redundant:如果不想要这个service worker了,可以unregister, 或者stop,这个时候就会进入废弃状态。
2)事件
有三个重要的功能性事件,fetch,push,sync。
fetch:hook主页面全部的网络请求。
push:如果订阅了后台推送事件,可以使用推送方式唤醒 Service Worker 以响应来自系统消息传递服务的消息,即使用户已经关闭了页面。
sync:sync 事件由 background sync (后台同步)发出。background sync 配合 Service Worker 推出的 API,用于为 Service Worker 提供一个可以实现注册和监听同步处理的方法(还没用过)。
如何在angualr5中使用service worker?
angular5提供了一个serviceWorker模块。我们只要定义好缓存的规则,就可以轻松的使用service worker了~
材料准备:与当前angular版本匹配的service worker版本。这里需要注意版本一定要相对应,否则会发生activate但不可用的情况。本地"@angular/service-worker": "^5.2.0"。
npm i @angular/service-worker
修改angular-cli.json
"app": {
"serviceWorker": true,
}
引入service-worker:
在app.moudule.ts中引入service-worker。需要注意service-worker需要工作在production环境。所以引入方式如下:
imports: [
BrowserModule,
environment.production ? ServiceWorkerModule.register('/ngsw-worker.js') : [],
]
其中register的路径在相对于cdn静态资源的位置而言。当app.moudule运行在该位置的时候,需要ngZone处在stable的状态,否则不会注册seviceWorker。因此为了防止这种情况,采用手动注册的方法。如:
platformBrowserDynamic().bootstrapModule(AppModule).then(()=>{
if(navigation.serviceWorker && !navigation.serviceWorker.controller){
navigation.serviceWorker.register('/ngsw-worker.js');
}
})
.catch(err => console.log(err));
接着需要为serviceWorker准备config.json,指定哪些静态资源,哪些api对应的数据,需要缓存,以及遵循的缓存策略。在src目录下创建文件ngsw-config.json.
{
"index": "/index.html",
"assetGroups": [{
"name": "app",
"installMode": "prefetch",
"resources": {
"files": [
"/favicon.ico",
"/index.html"
],
"versionedFiles": [
"/*.bundle.css",
"/*.bundle.js",
"/*.chunk.js"
]
}
}, {
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch",
"resources": {
"files": [
"/assets/**"
]
}
}],
"dataGroups": [
{
"name": "public-url",
"urls": ["/users/", "loginV2"],
"cacheConfig": {
"strategy": "freshness",
"maxSize":100,
"timeout": "1s"
}
},{
"name": "public-cache-url",
"urls": ["/tags", "/nation"],
"cacheConfig": {
"strategy": "freshness",
"maxSize":100,
"maxAge": "10d",
"timeout": "1s"
}
}
]
}
index: 指定根页面文件,一般是index.html
assetsGroup: 缓存的静态文件,一般为页面需要的js,css。assets文件下一般存有文件需要的静态资源,也可以设置缓存。
dataGroup:对应api获取的数据,所采取的缓存策略。
service-worker提供两种缓存策略:
- lazy模式:在需要的时候缓存,当该资源被请求的时候,才缓存它。
- prefetch:标明该资源对于app很重要,在install的时候,就提前请求并保存下来。
可以在两种事件中应用以上两种缓存策略,一个是installMode,一个是updateMode。
- installMode: 当serviceWorker第一次注册,并且第一次设置缓存的时候。
- updateMode: 当assetsgroup有新版本的时候。
dataGroup也应用同样的缓存策略。写法与assetsGroup略有不同。
urls:指定应用该策略的的url规则。
cacheConfig:指定urls下的缓存规则:
- strategy:缓存规则,分为fressness 和performance两种。fressness表示先从网络拉去数据,如果获取失败,则应用本地缓存。performance标明优先使用本地缓存,如果失败,再从网络获取。
- maxSize:表明该规则下最多能缓存多少条数据
- maxAge:表明缓存的有效存续事件
- timeout:指应用某种类数据,到获取失败使用备用数据,中间的等待事件。例如:如果是fressness,timeout=1s,表示先从网络获取数据,如果1s内还没有得到数据,则使用缓存。
当写好自己的service-worker的时候,运行命令,
ng build --prod
文件打包完之后,可以在dist目录下,看到angularWorkerModule生成的ngsw-worker.js和ngsw-config.json。
启动服务,打开开发者工具applicaiton service-worker,即可发现脚本注册在指定域名下了。这里需要注意的是service-worker需要运行在https上,所以本地域名必须支持https。
运行一段事件之后,断开网络再访问该页面,发现可以无障碍的使用已经加载过的页面(如果没有新数据的产生)。
ngsw-worker.js到底做了什么?
到此service-worker已经可以使用了。不过我们还想看看service-worker的缓存到底是如何实现的。以下分析下ngsw-worker.js的内容。
内容太多。。。另起一篇。