0%

H5离线缓存


我们浏览网页的时候经常遇到断网,这时候网页就提示失败了,对用户的体验很不好,前端是可以进行离线缓存的,一起看看怎么实现

记得两年前用过离线缓存,用的是manifest,当时用的兴高采烈,配置一下就完事了,今天打开一看,报错了,.manifest文件不识别,web服务器未配置,依稀记得使用node服务器的express框架的时候,自动就会识别的,查一下文档,发现这个马上就要被弃用了,得了,学习一下H5新的离线缓存吧

Service Worker实现缓存

service worker也称服务器工作线程,是浏览器在后台独立网页运行的脚本。我们平常浏览器窗口中跑的页面运行的是主JavaScript线程,DOM和window全局变量都是可以访问的。而Service Worker是走的另外的线程,可以理解为在浏览器背后默默运行的一个线程,脱离浏览器窗体,因此,window以及DOM都是不能访问的,此时我们可以使用self访问全局上下文。

出于安全原因,Service Workers 要求必须在 HTTPS 下才能运行。为了便于本地开发,localhost 也被浏览器认为是安全源。

生命周期

我是图片

总结起来Service Worker的生命周期有如下几个关键步骤(就是常常需要监听并制定回调函数的事件):

  1. 注册(register)当你的应用未注册过service worker,那么第一步就是注册;
  2. 安装(install),注册完成之后,会触发install,在这一步我们可以进行文件缓存;
  3. 响应请求(fetch),fetch用于拦截用户请求,并响应,返回Promise对象,成功安装service worker后,待用户下次再进入页面,返回已返回的文件。
  4. 更新(activate),当网站上当前页面被关闭,旧服务线程被终止。重新打开网页时,新服务工作线程取得控制权后,会触发activate事件。这一步我们可以清楚就版本缓存。
  5. 销毁,是否销毁由浏览器决定,如果一个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
// 用于标注创建的缓存,也可以根据它来建立版本规范
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));
}
});

差不多就是这样的啦,有一些其他的功能还没有研究透,到时候再来补上,有兴趣的小伙伴可以看看官网文档 戳我戳我

以上就是我对离线缓存的一些理解,如果文章由于我学识浅薄,导致您发现有严重谬误的地方,请一定在评论中指出,我会在第一时间修正我的博文,以避免误人子弟。

-------------本文结束感谢您的阅读-------------
没办法,总要恰饭的嘛~~