推荐阅读:Service Worker 简介
在 Service Worker 之前,我们一般用 AppCache 来实现离线体验(就是配置 Manifest 文件的方式),这个会有很多问题(博主曾尝试过,体验非常差,非常难用,而且不灵活)。
而 Service Worker 可以写脚本去灵活自由地控制缓存。
基本使用:
1. 注册
<!-- /report/index.html 片段 --> <script> if (navigator.serviceWorker) { navigator.serviceWorker.register('./sw.js').then(res => { console.log('注册成功'); // serviceWorker 是有作用域的,这里作用域是/report,如果是其他路径(例如/alarm)用到这个serviceWorker,它也不会工作。但是/report/**/* 都是可以生效的 console.log('作用域是:' + res.scope); }).catch(e => { console.log('注册失败'); }) } </script>
2. 安装
// /report/sw.js 片段 const CACHE_NAME = 'my-cache'; const cacheList = ['./index.html'] this.addEventListener('install', ev => { // waitUntil 传入 Promise,判断安装时间和成功与否 ev.waitUntil( // 如果有则打开,不存在则创建这个 'my-cache' 缓存空间 caches.open(CACHE_NAME).then(myCache => { // 往缓存里面存文件 // return 出去形成 Promise 链,否则,caches.open 成功后, waitUntil 就以为已经安装成功了 return myCache.addAll(cacheList); }) ) })
3. 拦截请求并缓存
// /report/sw.js 片段 const CACHE_NAME = 'my-cache'; //.... this. addEventListener('fetch', ev => { // respondWith 传入一个 Promise,作为返回给页面的响应 ev.respondWith( // 在所有缓存里面找是否有e.request的缓存 caches.match(ev.request).then(res => { if (res) { return res; } return fetch(ev.request).then(res => { // 缓存的res需要先克隆,因为 res 会先 return 出去给页面使用,被使用后的 res 添加缓存会报错 const resClone = res.clone(); // 缓存新请求 caches.open(CACHE_NAME).then(cache => { cache.put(ev.request, resClone); }) return res; }) }) ) })
不克隆,直接加入缓存会报错