本文目的主要是记录我对 HTTP 缓存机制和 ServiceWorker 的 cacheStorage 的缓存机制的理解
目前我对 ServiceWorker 还处于了解中,可能会出现较多的错误,欢迎指出。
浏览器缓存
浏览器缓存是指浏览器端用于在本地保存数据并进行快速读取的以避免重复资源请求的传输机制的统称。
打开Chrome浏览器,进入开发者工具,在Application那,你会发现有 HTTP 文件缓存、LocalStroage、SessionStorage、indexDB、Web SQL、Cookie、CacheStorage和Application Cache 。
这里只介绍 HTTP 文件缓存 和 Application Cache
HTTP 文件缓存
HTTP 文件缓存是基于 HTTP 协议的浏览器文件级缓存机制。这套机制决定了浏览器在文件重复请求时判断是否更新文件还是从本地读取文件。
流程图如下:
流程图步骤说明:
- 浏览器会先查询
Cache-Control
来判断内容是否过期,未过期则直接读取缓存文件,不发送 HTTP 请求,否则进入步骤2 - 浏览器判断上次文件的响应头是否有
Etag
,有则连同If-None-Match
一起发送请求,由服务器判断Etag
,如未修改则返回304,修改则返回200,否则进入步骤3 - 浏览器判断上次文件的响应头是否有
Last-Modified
,有则连同If-Modified-Since
一起发送请求,由服务器判断Last-Modified
,失效则返回200,未失效则返回304 Etag
和Last-Modified
都没有,则直接200
补充说明:Cache-Control
跟 Expires
是类似的,但前者指的是相对过期时间,后者指的是绝对过期时间,如果两者同时设置,则只有 Cache-Control
生效
缓存时长计算公式:缓存时长 = 响应时间 + 缓存寿命 - 当前时间
响应时间指浏览器接收到服务端的响应的时间
如需了解更多,可以查看我另外一篇博文:Here
cacheStorage
如果对 PWA 有所了解的话同学应该知道 PWA 的离线能力就是由 cacheStorage 提供,所以这部分也是成为重点部分。
在讲解 cacheStorage 先介绍一下 Application Cache 。
Application Cache 是一种允许浏览器通过 manifest 配置文件在本地有选择性地存储静态资源的文件级缓存机制。页面第二次以后打开,资源将会根据 manifest 配置描述有选择地读取本地 Application Cache 里面的文件。优势主要有:1、离线访问;2、加载速度快;3、服务器负载小。但缺点也很明显,包括:1、开始被标准弃用;不兼容主流(移动)浏览器;3、容量仅有5MB;4、资源失效时,更新也跟着失效;5、manifest要同源等等
这里再提一下 RAIL ,一个以用户为中心的性能模型,看到这里,你就知道了 Application Cache 其实并不怎么符合 RAIL
终于可以讲 cacheStorage 了
Google 强势推 PWA 以及其支持的技术,其中就有 ServiceWorker。cacheStorage 就是在 ServiceWorker 规范中定义的,用于保存每个 ServiceWorker 声明的 Cache 对象。
cacheStorage 在 Chrome 浏览器端里全局内置了 caches 对象,通过五个核心 API 方法直接对 Cache 对象进行操作,如下:
- caches.match() : 匹配key中含有该字符串的 Cache 对象,有返回一个 Promise 对象
- caches.has() : 检查是否包含 Cache 对象,是则返回一个 Promise 对象
- caches.open() : 打开或新建一个 Cache 对象并返回一个 Promise 对象
- caches.delete() : 成功找到和删除 Cache 对象并返回一个 Promise 对象,否则返回false
- caches.keys() : 遍历所有 Cache 对象,当含有keys中字符串的任意一个时返回一个 Promise 对象
要了解 cacheStorage 就得深入了解 ServiceWorker,ServiceWorker 与 WebWorker 一样是在浏览器后台作为一个独立的线程去运行JavaScript,并通过 message 与 postMessage 方法在页面之间通信。移动端的原生应用一般都有消息推送、离线使用、自动更新等能力。如果使用 ServiceWorker 也可以让 Web 应用具备类似的能力。
在使用 ServiceWorker 时,通常需要先注册 一个 ServiceWorker JavaScript脚本,然后在里面写入 caches 的缓存控制方法,下图为 ServiceWorker 运行的生命周期
注册 ServiceWorker
if(navigator.serviceWorker){
navigator.serviceWorker.register('./sw.js').then(function(registration){
console.log('sw注册成功');
}).catch(function(e){
console.log('sw注册失败');
});
}
sw.js里的缓存列表
let cacheList = ['index.js','index.css'];
将缓存列表注册到 cacheStorage 里,使用caches管理
this.addEventListener('install', function(event){
event.waitUntil(
caches.open('indexCache').then(function(cache){
return caches.addAll(cacheList);
})
);
});
监听 ServiceWorker 的 fetch 方法,如果有响应则使用响应,否则读取缓存
this.addEventListener('fetch', function(event){
event.respondWith(cacnes.match(event.request).then(function(response){
if(response){
return response;
}
let responseToCache = response.clone();
caches.open('indexCache').then(function(cache){
cache.put(event.request, responseToCache);
});
}));
});
更多关于 ServiceWorker 的介绍可以查看:Here
总结
通过横向了解 HTTP 文件缓存机制 和 ServiceWorker的cacheStorage,我们可以知道,前者是一种基于客户端的缓存策略,比较固定,而后者则是一种基于页端缓存策略,极具自由和可定制。
内容不多,大概就这样...
本文由 Chakhsu Lau 创作,采用 知识共享署名4.0 国际许可协议进行许可。
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。