随着浏览器功能的日益强大,在工作中,浏览器是前端工程师们最重要的战友和开发调试工具,它承载着用户最舒适的用户体验,ui最佳的设计成果展示,后台数据最直观的展示。因此,对浏览器的认识和理解起到举足轻重的地位,现学习浏览器的缓存知识分享如下,欢迎各位
整个web应用简易流程如下图:
上述流程,哪些地方比较耗费时间
- 发送请求的时候
- 涉及大量运算的时候
- 查询响应数据也会消耗时间
缓存在很多地方都有运用
- 数据库缓存
- CDN缓存
- 代理服务器缓存
- 浏览器缓存
- 应用层缓存
整个浏览器的缓存基本过程如下图:
- 浏览器每次发请求,都会先到浏览器缓存中查找该请求的结果和缓存标识
- 浏览器每次拿到返回的响应结果都会将结果和缓存标识存入浏览器缓存中
按缓存的存储位置分类
从缓存的位置来说,分为四种,并且各有优先级,每次请求依次查找都没有才会去请求网络。
-
Service Worker(手动)
-
运行在浏览器背后的独立线程,一般用来实现缓存功能。类似于一个代理服务器
-
传输协议必须是https,因为Service Worker中涉及到请求拦截,所以必须用HTTPS来保障安全。
-
使用方法:注册–> 监听install事件–>缓存需要的文件
-
-
Memory Cache(自动)
-
内存中的缓存,读取速度快
-
内存容量小,关闭tab页面,内存中的缓存也就释放了。
-
-
Disk Cache (自动)
-
硬盘上的缓存,读取速度比内存缓存慢
-
时效性和容量大大优于 Memory Cache
-
浏览器会自动的根据HTTP Header中的字段判断哪些资源需要缓存,哪些资源可以不请求直接使用,哪些资源已经过期了需要重新请求。
-
浏览器会自动进行清理,算法会把最老的资源删除。
-
-
Push Cache
-
推送缓存。http/2(2015)中新增的内容
-
当以上三种缓存都没有使用才会被使用到
-
所有的资源的资源都会被推送,并且能够被缓存,但是Efge和safari浏览器支持相对较差。
-
可以推送no-cache和no-store的资源
-
一旦连接被关闭,Push Cache 就被释放
-
多个页面可以使用同一个HTTP/2的连接,也就可以使用同一个Push Cache,这主要还是依赖浏览器的实现而定,出于对性能的考虑没有的浏览器会对相同域名但不同的tab标签使用同一个HTTP连接
-
pushCache的缓存只能被使用一次
-
浏览器可以拒绝接收已经存在的资源推送
-
你可以给其他域名推送资源
-
-
按缓存的类型分类
分为 强制缓存 和 协商缓存
【注意】 无论是强制缓存还是协商缓存都是DiskCache或者叫做HTTPCache的一种
强制缓存
客户端发送请求,先访问缓存,有则返回,没有则请求服务器,响应再缓存
强制缓存减少请求数,是提升最大的缓存策略,
可以造成强制缓存的字段是 Cache-control 和 Expires
Expires
这是HTTP1.0的字段,表示缓存到期时间(绝对时间【当前时间+缓存时间】)
Expires:Thu,10 NOV 2017 08:11:33 GMT
在响应消息头中,设置这个字段之后,就可以告诉浏览器,在未过期之前不需要再次请求。
缺点:字段设置多个空格,少个字母,都会导致变为非法字符属性从而导致失效。时差和客户端修改时间也会导致缓存失效,所以不好用。
Cache-control
自从HTTP/1.1开始,Expires逐渐被Cache-control取代。
在http/1.1中,增加了该字段,该字段表示资源缓存的最大有效时间,在该时间内,用户不需要向服务器发送请求。
Cache-control是一个相对时间,即使客户端时间发生改变,相对时间也不会随之改变,这样可以保持服务器和客户端的时间一致性,而且Cache-control的可配置型比较强大,Cache-control的优先级高于Expires。
Cache-control设置的是相对时间:
Cache-control:max-age=2592000
Cache-control里的属性
- max-age:最大有效时间
- must-revalidate:超过最大有效时间,浏览器必须向服务器发送请求,验证资源是否有效
- no-store:不走缓存
- no-cache:不走缓存由协商缓存决定
- public:所有内容都被缓存
- private:所有内容只有客户端可以缓存,代理服务器不能缓存,默认值。
可混用有优先级,例如:
Cache-control:public,max-age=259200
为了兼容http1.0和http1.1,实际项目中Cache-control和Expires都会设置
协商缓存
强制缓存(强制时间内使用缓存)失效,比如max-age到期了,就要使用协商缓存(客户端向服务器发送请求,携带资源标识,服务器会把资源标识和服务器做对比,如果资源没发生改变,服务器就会返回304,告诉客户端资源无更新,客户端会继续使用缓存,如果资源有改变,服务器返回新的数据、缓存规则、200的code码,浏览器将新的规则写入缓存),由服务器决定缓存内容是否失效。
协商缓存的主要优化主要体现在响应上通过减少响应体体积,来缩短网络传输时间,所以强制缓存比提升幅度较小,但总比没有缓存好
协商缓存是可以强制一起使用的,作为在强制缓存失效后的一种后背方案。
协商缓存里的对比方式
- Last-Modified & If-Modified-since
- Etog & If-None-Match
Last-Modified & If-Modified-since
1.服务器通过Last-Modified字段告知客户端,资源最后一次被修改的时间
2.浏览器将这个值和内容一起记录在缓存数据库中
3.下一次请求相同的资源,浏览器会从自己的缓存中找到"不确定是否过期"的缓存,因此在请求头中将Last-Modified的值写入到请求头的If-Modified-since字段
4.服务器会将If-Modified-since的与last-modified的字段进行对比,如果相等,则表示未修改,响304,反之,则表示修改了,响应200状态码,并返回数据
缺陷:1.资源更新的速度是毫秒,那么该缓存是不能被使用的,因为它的时间单位最低是秒
2.文件如果是服务器动态生成的,那么该方法的更新时间永远是生成的时间,尽管文件可能没有变化,所以起不到缓存的作用。
所以http/1.1出现了 Etog & If-None-Match
Etog & If-None-Match
1.Etog存储的是文件的特殊标识(一般是一个hash值),服务器存储着文件的etog字符
2.浏览器请求资源,服务端返回资源和一个Elag
3.下一次请求,强缓失败,带着elog来找服务器要资源,即此在请求头中将elog写入到请求头的If-None-Match字段
4.资源未更新,返回304状态码
缓存读取规则
当浏览器请求资源时:
-
从Service Worker中获取内容(如果设置了Service Worker)
-
查看Memory Cache
-
查看Disk Cache。这里又细分:
- 如果有强制缓存,则使用强制缓存, 不请求服务器,这时的状态码全是200
- 如果有强制缓存但已失效,使用协商缓存,比较后确定时304还是200.
-
发送网络请求,等待网络响应
-
把响应的内容"自动"存入DiskCache(如果HTTP响应头有相应配置的话)
-
把响应内容的引用"自动"存入MemoryCache(无视http头信息的配置)
-
把响应内容存入Service Worker 的Cache Storage(如果设置了Service Worker)
浏览器行为
用户对浏览器的不同操作,会触发不同的缓存读取策略
- 正常打开网页,地址栏输入网址,查找Disk Cache是否匹配,有就是用,没有就正常发送请求
- f5刷新,tab没有关闭,优先使用memorycache,然后才是diskcache
- 强制刷新(ctrl+f5),浏览器不使用缓存,因此发送请求的头部带有Cache-control:no-cache(为了兼容还带有pragma:no-cache),服务器直接返回200和最新的内容。
缓存的最佳实践
对于频繁变动的资源
对于经常发生变化的资源,可以再响应头设置 Cache-control:no-cache ,使浏览器每次都请求服务器,配合ETog(比对hash)或Lat-Modified(比对时间戳)来验证资源是否有效。
这样的做法虽然不能节省请求的数量,但是因为服务端资源无变化,比对成功,服务端就会返回304,所以会减少请求的数据大小,不用每次都返回200和数据。
对于不常变化的资源
再处理这类资源,通常会配置一个很大的max-age=31536000(一年),这样浏览器之后请求相同的URL会命中强制缓存。
为了解决更新的问题,就需要在文件名(或者路径)中添加Hash,版本号等动态字符,从而达到更改URL的目的,由于这样设置会使请求的资源不同,所以强制缓存也就不再使用,浏览器会重新发送请求,进入协商缓存。