1. PWA和Service Worker的关系javascript
PWA (Progressive Web Apps) 不是一项技术,也不是一个框架,咱们能够把她理解为一种模式,一种经过应用一些技术将 Web App 在安全、性能和体验等方面带来渐进式的提高的一种 Web App的模式。对于 webview 来讲,Service Worker 是一个独立于js主线程的一种 Web Worker 线程, 一个独立于主线程的 Context,可是面向开发者来讲 Service Worker 的形态其实就是一个须要开发者本身维护的文件,咱们假设这个文件叫作 sw.js。经过 service worker 咱们能够代理 webview 的请求至关因而一个正向代理的线程,fiddler也是干这些事情),在特定路径注册 service worker 后,能够拦截并处理该路径下全部的网络请求,进而实现页面资源的可编程式缓存,在弱网和无网状况下带来流畅的产品体验,因此 service worker 能够看作是实现pwa模式的一项技术实现。html
2. service worker简介前端
注意事项vue
生命周期java
工做流程webpack
注册web
if(navigator && navigator.serviceWorker) { navigator.serviceWorker.register('/service-worker.js').then(function (registration) { console.log(registration) }).catch(function (err) { console.log(err) }) }
安装chrome
var cacheVersion = 'test_2017122608'; // 安装服务工做线程 self.addEventListener('install', function(event){ // 须要缓存的资源 var cacheFiles = [ '/dist/index.html', '/dist/js/index_async_bundle.js' ]; console.log('service worker: run into install'); event.waitUntil(caches.open(cacheVersion).then(function(cache) { return cache.addAll(cacheFiles); })); });
激活npm
// 新的service worker线程被激活(其实和离线包同样存在"二次生效"的机理) self.addEventListener('activate', function (event) { console.log('service worker: run into activate'); event.waitUntil(caches.keys().then(function (cacheNames) { return Promise.all(cacheNames.map(function (cacheName) { // 注意这里cacheVersion也能够是一个数组 if(cacheName !== cacheVersion){ console.log('service worker: clear cache' + cacheName); return caches.delete(cacheName); } })); })); });
监听编程
// 拦截请求并响应
self.addEventListener('fetch', function (event) { console.log('service worker: run into fetch'); event.respondWith(caches.match(event.request).then(function (response) { // 发现匹配的响应缓存 if(response){ console.log('service worker 匹配并读取缓存:' + event.request.url); return response; } console.log('没有匹配上:' + event.request.url); return fetch(event.request); /*var fetchRequest = event.request.clone(); return fetch(fetchRequest).then(function(response){ if(!response || response.status !== 200 || response.type !== 'basic'){ return response; } var responseToCache = response.clone(); caches.open(cacheVersion).then(function (cache) { console.log(cache); cache.put(fetchRequest, responseToCache); }); return response; });*/ })); });
3. 前端资源缓存演进
4. 项目如何快速接入service worker
咱们是在业务代码中经过register的方式引入service-worker.js, 那问题就变为如何在注册服务工做线程的位置引入版本号呢,咱们能够经过sw-register-webpack-plugin来解决该问题,其思路是将服务工做线程的注册放在一个单独的文件中(sw-register.js),而后自动在页面入口(例如index.html)写入一段JS脚原本动态加载sw-register.js文件,这里sw-register.js的加载路径是带有实时时间戳的,而生成的sw-register.js文件内容中注册service-worker.js的位置自动携带构建版本号参数(默认是当前构建时间),该插件配置以下(基于webpack构建的项目):
let SwRegisterWebpackPlugin = require('sw-register-webpack-plugin') ... plugins: [ new SwRegisterWebpackPlugin({ filePath: path.resolve(__dirname, '../src/sw-register.js') }) ]
已缓存资源文件如何更新呢?上述插件只是解决了service-worker.js文件自己的更新的问题(保证每次构建部署后会新启一个服务工做线程),但对于service-worker.js文件中定义的cacheFiles而言,当咱们修改了已缓存文件后如何来更新缓存呢,个人项目是基于vue.js + webpack,打包后的JS文件是[name].[hash].[ext]格式,从前面的介绍可知资源的缓存也是基于url(做为key)来的,不可能每次构建后都手动去调整service-worker.js文件内容中cacheFiles的路径值吧,应该是将构建后的文件名(包括路径)直接放到service-worker.js内容中,看到这里你应该想到了有webpack插件已经帮咱们作好了,那就是sw-precache-webpack-plugin,该插件会自动在dist目录下生成service-worker.js文件,供给service worker运行,也就是说service-worker.js文件自己不须要咱们手动添加了,但问题是咱们如何自定义须要缓存的文件呢,该插件的配置参数会告诉你,个人项目该插件配置以下:
// 生成service-worker.js和配置缓存清单 new SwPrecacheWebpackPlugin({ cacheId: 'attendance-mobile-cache', filename: 'service-worker.js', minify: true, dontCacheBustUrlsMatching: false, staticFileGlobs: [ 'dist/static/js/manifest.**.*', 'dist/static/js/vendor.**.*', 'dist/static/js/app.**.*' ], stripPrefix: 'dist/' })
4. 调试service worker
5. 异常回滚(注销)
某些场景下若是service worker使用出现异常,好比不一样页面间 service worker 控制的scope存在“重叠污染”的问题,那么咱们就须要紧急回滚(撤销)当前 service worker,在开发环境很好解决,咱们依然能够经过Chrome Devtools来进行unregister, 那么在线上环境已经有服务工做线程在运行的状况下呢,咱们须要在新上线版本的service worker注册前将被污染或者异常的service worker注销掉,具体代码以下:
if (navigator.serviceWorker) { navigator.serviceWorker.getRegistrations().then(function (registrations) { for (var item of registrations) { if (item.scope === 'http://localhost/attendance-mobile/dist/') { item.unregister(); } } // 注销掉污染 Service Worker 以后再从新注册... }); }
备注:文中部份内容摘选自Google开发者文档
原文直通车