缓存位置的类型
缓存位置有四种,各自有优先级,当依次查找缓存且都没有命中的时候,才会去请求网络。
- Service Worker
- Memory Cache
- Disk Cache
- Push Cache
Service Worker
- Service Worker 是一个服务器与浏览器之间的中间人角色,如果网站注册了Service Worker就可以拦截当前网站所有的请求,进行判断(需要编写相应的判断程序),需要向服务器发起请求的就转给服务器,可以直接使用缓存的就直接返回缓存不再转给服务器。从而大大提高浏览体验。
- Service Worker 是运行在
浏览器背后的独立线程
,一般可以用来实现缓存功能。基于h5的web worker,所以绝对不会阻碍当前js线程的执行。 - 最重要的工作原理就是:
后台线程:独立于当前网页线程;网络代理:在网页发起请求时代理,来缓存文件;
- 使用 Service Worker的话,
传输协议必须为 HTTPS
。因为 Service Worker 中涉及到请求拦截,所以必须使用 HTTPS 协议来保障安全。 - 1.开发者工具中的Application中查看是否使用Service Worker;2.被Service Worker缓存的文件,可以在Network中看到Size项为 from Service Worker;3.也可以在Application的Cache Storage中查看缓存的具体内容;
- Service Worker 的缓存与浏览器其他内建的缓存机制不同,它可以让我们自由控制缓存哪些文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。
Memory Cache
- Memory Cache是
内存中的缓存
,主要包含的是当前中页面中已经抓取到的资源,例如页面上已经下载的脚本等。再次访问时不会请求服务器。 - 读取内存中的数据肯定比磁盘快
缓存持续性很短
,会随着进程的释放而释放。 一旦我们关闭 Tab 页面,内存中的缓存也就被释放了。再次重新打开相同页面时不会出现from memory cache的情况内存缓存中有一块重要的缓存资源是preloader相关指令下载的资源。
总所周知preloader的相关指令已经是页面优化的常见手段之一,它可以一边解析js/css文件,一边网络请求下一个资源。- 内存缓存在缓存资源时并不关心返回资源的HTTP缓存头Cache-Control是什么值,同时资源的匹配也并非仅仅是对URL做匹配,还可能会对Content-Type,CORS等其他特征做校验。
Disk Cache
- Disk Cache是
存储在磁盘中的缓存
。再次访问时不会请求服务器。 读取速度慢点
- 资源不会随着该页面的关闭而释放掉,比之 Memory Cache 胜在
容量和存储时效性上
。 - Disk Cache 覆盖面基本是最大的。它会根据 HTTP Herder 中的字段判断哪些资源需要缓存,哪些资源可以不请求直接使用,哪些资源已经过期需要重新请求。并且即使在跨站点的情况下,相同地址的资源一旦被硬盘缓存下来,就不会再次去请求数据。
绝大部分的缓存都来自 Disk Cache
。
Push Cache
Push Cache(推送缓存)是 HTTP/2 中的内容,在国内能够查到的资料很少,有以下结论:
- 所有的资源都能被推送,并且能够被缓存,但是 Edge 和 Safari 浏览器支持相对比较差
- 可以推送 no-cache 和 no-store 的资源
- 一旦连接被关闭,Push Cache 就被释放
- 多个页面可以使用同一个HTTP/2的连接,也就可以使用同一个Push Cache。这主要还是依赖浏览器的实现而定,出于对性能的考虑,有的浏览器会对相同域名但不同的tab标签使用同一个HTTP连接。
- Push Cache 中的缓存只能被使用一次
- 浏览器可以拒绝接受已经存在的资源推送
- 你可以给其他域名推送资源
Service Worker使用流程
注册Service worker,在index.html加入以下代码
/* 判断当前浏览器是否支持serviceWorker */
if ('serviceWorker' in navigator) {
/* 当页面加载完成就创建一个serviceWorker */
window.addEventListener('load', function () {
/* 创建并指定对应的执行内容 */
/* scope 参数是可选的,可以用来指定你想让 service worker 控制的内容的子目录。 在这个例子里,我们指定了 '/',表示 根网域下的所有内容。这也是默认值。 */
navigator.serviceWorker.register('./serviceWorker.js', {scope: './'})
.then(function (registration) {
console.log('ServiceWorker registration successful with scope: ', registration.scope);
.catch(function (err) {
console.log('ServiceWorker registration failed: ', err);
});
});
}
安装worker:在我们指定的处理程序serviceWorker.js中书写对应的安装及拦截逻辑
/* 监听安装事件,install 事件一般是被用来设置你的浏览器的离线缓存逻辑 */
this.addEventListener('install', function (event) {
/* 通过这个方法可以防止缓存未完成,就关闭serviceWorker */
event.waitUntil(
/* 创建一个名叫V1的缓存版本 */
caches.open('v1').then(function (cache) {
/* 指定要缓存的内容,地址为相对于跟域名的访问路径 */
return cache.addAll([
'./index.html'
]);
})
);
});
/* 注册fetch事件,拦截全站的请求 */
this.addEventListener('fetch', function(event) {
event.respondWith(
// magic goes here
/* 在缓存中匹配对应请求资源直接返回 */
caches.match(event.request)
);
});
Service Worker是有对应的事件名进行捕获的,为:
- self.addEventListener(‘install’, function(event) { /* 安装后… */ });
- self.addEventListener(‘activate’, function(event) { /* 激活后… */ });
- self.addEventListener(‘fetch’, function(event) { /* 请求后… */ });
基本上,目前Service Worker的所有应用都是基于上面3个事件的,例如,本文要介绍的缓存和离线开发,'install’用来缓存文件,'activate’用来缓存更新,'fetch’用来拦截请求直接返回缓存数据。三者齐心,构成了完成的缓存控制结构。
注意事项
- Service worker运行在worker上下文 --> 不能访问DOM
- 它设计为完全异步,同步API(如XHR和localStorage)不能在service worker中使用
- 出于安全考量,Service workers只能由HTTPS承载
- 在Firefox浏览器的用户隐私模式,Service Worker不可用
- 其生命周期与页面无关(关联页面未关闭时,它也可以退出,没有关联页面时,它也可以启动)
访问缓存优先级(三级缓存原理 )
- 先在内存中查找,如果有,直接加载。
- 如果内存中不存在,则在硬盘中查找,如果有直接加载。
- 如果硬盘中也没有,那么就进行网络请求。
- 请求获取的资源缓存到硬盘和内存。
chrome控制台Network中size的三种状态
- from memory cache:从内存中拿到的资源
- from disk cache:从磁盘中读取到的资源
- 资源本身大小数值:当http状态为200是实实在在从浏览器获取的资源,当http状态为304时该数字是与服务端通信报文的大小,并不是该资源本身的大小,该资源是从本地获取的
统计表
状态 | 类型 | 说明 |
---|---|---|
200 | form memory cache | 不请求网络资源,资源在内存当中 |
200 | form disk ceche | 不请求网络资源,在磁盘当中 |
200 | 资源大小数值 | 从服务器下载最新资源 |
304 | 报文大小 | 请求服务端发现资源没有更新,使用本地资源 |
- 由此可见样式表一般在磁盘中,不会缓存到内存中去,因为css样式加载一次即可渲染出网页
- 但是脚本却可能随时会执行,如果脚本在磁盘当中,在执行该脚本需要从磁盘中取到内存当中来,这样的IO开销是比较大的,有可能会导致浏览器失去响应
Firefox的缓存策略
- 在Firefox下并没有from memory cache以及from disk cache的状态展现,相同的资源在chrome下是from disk/memory cache,但是
Firefox统统是304状态码
- 即Firefox下会缓存资源,但是
每次都会请求服务器对比当前缓存是否更改
,chrome不请求服务器,直接拿过来用