/ 前端
分类:前端来源:站内 最近更新:2020-10-07 11:22:26浏览:1579留言:0
我们在用VUE-CLI创建项目的时候,有个"Progressive Web App (PWA) Support"选项,勾选上之后就会在src目录里生成registerServiceWorker.js的文件,代码如下:
/* eslint-disable no-console */ import { register } from "register-service-worker"; if (process.env.NODE_ENV === "production") { register(`${process.env.BASE_URL}service-worker.js`, { ready() { console.log( "App is being served from cache by a service worker.\n" + "For more details, visit https://goo.gl/AFskqB" ); }, registered() { console.log("Service worker has been registered."); }, cached() { console.log("Content has been cached for offline use."); }, updatefound() { console.log("New content is downloading."); }, updated() { console.log("New content is available; please refresh."); }, offline() { console.log( "No internet connection found. App is running in offline mode." ); }, error(error) { console.error("Error during service worker registration:", error); } }); }
2015年互联网+时代的到来,让Native App的安卓开发和IOS开发火了一把,当热潮消退之后,Native APP的缺点也慢慢的暴露出来:
开发成本高,因为这个行业刚刚兴起,人才很紧缺,不仅薪资高,而且真正的经验也有限。
一个APP要上传到不同的应用商店,大大小小的不下20个。
版本上线需要各个应用商店的审核,尤其遇到大版本迭代和搞活动。时间上的控制会让公司疯掉
所以,很多公司又把目光转移到web端的H5上,但是web的缺点依旧是有的,至少体验上没有Native APP好,没有网路就不能打开,不具备离线的能力。所以慢慢的,PWA渐进式WEB应用诞生了,PWA的离线功能就是用Service Worker来实现的。
Service worker是一个注册在指定源和路径下的事件驱动woker。它采用JavaScript控制关联的页面或者网站,拦截并修改访问和资源请求,细粒度地缓存资源。你可以完全控制应用在特定情形(最常见的情形是网络不可用)下的表现。(官方描述);
如果熟悉Web Worker,了解Service Worker就简单了。JS是单线程的,但是单线程已经满足不了快节奏的趋势,如何解决这个弊端,Web Worker 和 Service Worker就创造出来了,他们是在主线程之外独立运行的线程。通过postMessage和onMessage和主线程相互通信。Service Worker具备以下特点:
独立的线程,在web worker的基础上增加了离线缓存的能力
无法操作DOM
本质上充当Web应用程序(服务器)与浏览器之间的代理服务器(可以拦截全站的请求,并作出相应的动作->由开发者指定的动作)
只能使用HTTPS以及localhost(测试环境修改host文件绑定)
由事件驱动的,具有生命周期
可以访问cache和indexDB
一旦被 install,就永远存在,除非被 uninstall或者dev模式手动删除
支持推送
并且可以让开发者自己控制管理缓存的内容以及版本
Service worker大部分应用在H5手机web端,所以市面上的大部分手机浏览器应用都支持了。如果不支持,JS里加上判断,对整个程序完全没有任何影响。
注册事件由主线程发起,注册一个serviceWorker,如文章最顶部VUE脚手架自带的文件,用户打开页面时,开始注册Service Workder.
installing 注册中会触发 install 事件,serviceWorker都是事件触发的方式进行的逻辑调用,如果事件里有 event.waitUntil() 则会等待传入的 Promise 完成才会成功
注册完成,如果之前有就的Service Worker脚本控制,直接通过self.waitUntil()跳过等待
安装完成后,开始进入激活activating,
等待event.waitUntil()完成后,出发activated
当用户再次刷新页面或者再次进入后,先读取serviceWorker存的版本资源,如果有变化,会重新触发生命周期。
1、先创建一个主程序用于加载独立的线程js文件(当然这边的方式有很多种,可以是blob流,也可以用script的方式写)。
核心代码如下:
if ('serviceWorker' in navigator) { navigator.serviceWorker.register('service-worker.js'); }
vue脚手架会自动在src里建立registerServiceWorker.js,核心代码文章顶部。下面就以vue-cli脚手架为实战练习
2、根据代码${process.env.BASE_URL}service-worker.js,需要在public目录下新建一个service-worker.js文件。
编辑代码如下:
var CACHE_VERSION = "app-v1"; // 缓存文件的版本 var CACHE_FILES = [ // 需要缓存的页面文件 "/" ]; self.addEventListener("install", function(event) { // 监听worker的install事件 event.waitUntil( // 延迟install事件直到缓存初始化完成 caches.open(CACHE_VERSION).then(function(cache) { console.log("Opened cache"); return cache.addAll(CACHE_FILES); }) ); }); self.addEventListener("activate", function(event) { // 监听worker的activate事件 event.waitUntil( // 延迟activate事件直到 caches.keys().then(function(keys) { return Promise.all( keys.map(function(key, i) { // 清除旧版本缓存 if (key !== CACHE_VERSION) { return caches.delete(keys[i]); } }) ); }) ); }); self.addEventListener("fetch", function(event) { // 截取页面的资源请求 event.respondWith( // 返回页面的资源请求 caches.match(event.request).then(function(res) { // 判断缓存是否命中 if (res) { // 返回缓存中的资源 return res; } requestBackend(event); // 执行请求备份操作 }) ); }); function requestBackend(event) { // 请求备份操作 var url = event.request.clone(); return fetch(url).then(function(res) { // 请求线上资源 //if not a valid response send the error if (!res || res.status !== 200 || res.type !== "basic") { return res; } var response = res.clone(); caches.open(CACHE_VERSION).then(function(cache) { // 缓存从线上获取的资源 cache.put(event.request, response); }); return res; }); }
注意:service-worker.js 不能出现任何操作dom的事件,如果真想触发,可以通过postMessage事件让主程序执行。
3、本地调试的时候,要把registerServiceWorker.js文件中判断生成环境的代码去掉,方便我们测试,后期上线可以再还原,npm run serve运行。
打开Chrome开发者工具,先情况所有缓存,然后刷新页面,发现Cache Storage存放了值
4、几次刷新的情况下,我们发现,页面资源都通过ServiceWorer缓存抓取了
5、然后我们关闭网络如下图,再次刷新,页面依旧能够访问。实现了离线缓存的方式。
ServiceWorer是PWA核心功能之一,PWA有还有消息推送等其他模拟Native APP的功能。我们在做离线缓存时要考虑项目的必要性,如果很多资源都是需要后端接口返回的实时数据,不建议离线缓存。而且要控制好缓存的机制,不然上线后发现页面没有更新。