我们浏览网页的时候经常遇到断网,这时候网页就提示失败了,对用户的体验很不好,前端是可以进行离线缓存的,一起看看怎么实现
记得两年前用过离线缓存,用的是manifest,当时用的兴高采烈,配置一下就完事了,今天打开一看,报错了,.manifest文件不识别,web服务器未配置,依稀记得使用node服务器的express框架的时候,自动就会识别的,查一下文档,发现这个马上就要被弃用了,得了,学习一下H5新的离线缓存吧
Service Worker实现缓存 service worker也称服务器工作线程,是浏览器在后台独立网页运行的脚本。我们平常浏览器窗口中跑的页面运行的是主JavaScript线程,DOM和window全局变量都是可以访问的。而Service Worker是走的另外的线程,可以理解为在浏览器背后默默运行的一个线程,脱离浏览器窗体,因此,window以及DOM都是不能访问的,此时我们可以使用self访问全局上下文。
出于安全原因,Service Workers 要求必须在 HTTPS 下才能运行。为了便于本地开发,localhost 也被浏览器认为是安全源。
生命周期
总结起来Service Worker的生命周期有如下几个关键步骤(就是常常需要监听并制定回调函数的事件):
注册(register)当你的应用未注册过service worker,那么第一步就是注册;
安装(install),注册完成之后,会触发install,在这一步我们可以进行文件缓存;
响应请求(fetch),fetch用于拦截用户请求,并响应,返回Promise对象,成功安装service worker后,待用户下次再进入页面,返回已返回的文件。
更新(activate),当网站上当前页面被关闭,旧服务线程被终止。重新打开网页时,新服务工作线程取得控制权后,会触发activate事件。这一步我们可以清楚就版本缓存。
销毁,是否销毁由浏览器决定,如果一个service worker长期不使用或者机器内存有限,则可能会销毁这个worker
注册 在index.html页面中去注册
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // 检查浏览器是否对 serviceWorker 有原生支持 if ('serviceWorker' in navigator) { // 有原生支持时,在页面加载后开启新的 Service Worker 线程,从而优化首屏加载速度 // 注册 service worker window.addEventListener('load', function() { // register 方法里第一个参数为 Service Worker 要加载的文件;第二个参数 scope 可选,用来指定 Service Worker 控制的内容的子目录 navigator.serviceWorker.register('./ServiceWorker.js',{scope: '/'}).then(function(registration) { // Service Worker 注册成功 console.log('ServiceWorker 注册成功: ', registration.scope); }).catch(function(err) { // Service Worker 注册失败 console.log('ServiceWorker 注册失败: ', err); }); }); }
安装 在index.html同级下创建ServiceWorker.js,在里面进行安装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 // 用于标注创建的缓存,也可以根据它来建立版本规范 const CACHE_NAME = "cs_cache_v1.0.0"; // 列举要默认缓存的静态资源,一般用于离线使用 const urlsToCache = [ '/index.html', './images/complete.jpg', './images/timeout.jpg', './js/TimeoutScene.js', './js/CompleteScene.js', ]; const offlineUrl = 'index.html'; // self 为当前 scope 内的上下文 //当页面加载时触发该事件。常用于缓存离线页面,当断开网络时,在该事件中缓存的页面将被返回给用户。 self.addEventListener('install', event => { // event.waitUtil 用于在安装成功之前执行一些预装逻辑 // 但是建议只做一些轻量级和非常重要资源的缓存,减少安装失败的概率 // 安装成功后 ServiceWorker 状态会从 installing 变为 installed event.waitUntil( // 使用 cache API 打开指定的 cache 文件 caches.open(CACHE_NAME).then(cache => { console.log(cache); // 添加要缓存的资源列表 return cache.addAll(urlsToCache); }) ); });
响应请求 也是在ServiceWorker.js下继续写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 this.addEventListener('fetch', event => { if(event.request.mode === 'navigate' || (event.request.method === 'GET' && event.request.headers.get('accept').includes('text/html'))) { event.respondWith( fetch(event.request.url).catch(error => { // Return the offline page return caches.match(offlineUrl); }) ); } else { event.respondWith(caches.match(event.request) .then(function(response) { return response || fetch(event.request); }) ); } });
更新 也是在ServiceWorker.js下继续写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 self.addEventListener('activate', event => event.waitUntil( Promise.all([ // 更新客户端 clients.claim(), // 清理旧版本 caches.keys().then(cacheList => Promise.all( cacheList.map(cacheName => { if(cacheName !== CACHE_NAME) { caches.delete(cacheName); } }) )) ]) ));
手动更新 其实在页面中,也可以手动来管理更新
1 2 3 4 5 6 7 const version = '1.0.1'; navigator.serviceWorker.register('/ServiceWorker.js').then(reg => { if (localStorage.getItem('sw_version') !== version) { reg.update().then(() => localStorage.setItem('sw_version', version)); } });
差不多就是这样的啦,有一些其他的功能还没有研究透,到时候再来补上,有兴趣的小伙伴可以看看官网文档 戳我戳我
以上就是我对离线缓存的一些理解,如果文章由于我学识浅薄,导致您发现有严重谬误的地方,请一定在评论中指出,我会在第一时间修正我的博文,以避免误人子弟。