浏览器缓存有先后顺序,总体分为以下四个方面:
Memory Cache
Service Worker Cache
Disk Cache
Push Cache
缓存位置
1. Memory Cache
内存中的缓存
优点:
浏览器会优先去命中的一种缓存
响应速度最快
缺点:
缓存时间短,关闭tab页面缓存将失效,与浏览器渲染进程紧密联系
2. Service Worker Cache
独立于主线程之外的javascript线程。脱离于浏览器窗体,因此无法直接访问DOM元素。因此这是一个独立的线程,能在不干扰主线程的情况下提升性能。
缓存三个步骤:
注册Service Worker
监听install事件,即可缓存需要的文件
用户下次访问可通过拦截请求的方式获取缓存数据,若没有就会重新获取数据,然后再进行缓存。
可以实现:离线缓存、消息推送、以及网络代理等功能。
Disk Cache
硬盘缓存
缓存位置在电脑硬盘上,
优点:
什么文件都可以缓存;
覆盖面最广,可以根据HTTP Header中的字段判断哪一些资源需要缓存,那些可以不请求直接用,哪些已过期需要重新请求。
缺点:
读取速度慢
Push Cache
推送缓存,国内使用较少。
缓存策略
分为两种:强缓存和协商缓存
一次HTTP请求流程:浏览器第一次发起请求,实现询问浏览器有没有缓存,没有就向服务器进行请求,然后结果进行缓存。
示意如下图:
强缓存
利用HTTP头部的Expires和Cache-Control两个字段来控制。
当请求再次发出,浏览器会根据expires和cache-control判断目标资源是否“命中”强缓存,命中就直接从缓存中获取资源,没有则再和服务端通信。
expires是时间戳,二次请求想服务器请求资源时,刘娜力气会先对比本地时间和expires的时间戳,若本地时间小于expires设定的过期时间,就直接去缓存中取这个资源。但expires得本地时间可以手动改,因此不太可靠。所以Cache-Control这个方法。
Cache-Control是个时间长度,以下几个字段较常见
- 通过max-age控制资源的有效期,,s-maxage是代理服务器的缓存时间。客户端中以max-age为准。
- 针对资源能否被代理服务缓存而存在:public和private
如果为资源设置了public,那么既可以被浏览器缓存,也可以被代理服务器缓存;若设置了private,那么只能被浏览器缓存。默认private - no-store 不适用任何缓存策略,只允许直接向服务端发送请求,并下载完整的响应;
no-cache 绕开了浏览器,每一次发起请求都不会再去询问浏览器的缓存情况,而是直接向服务端确认该资源是否过期(协商缓存)
协商缓存
依赖于服务端与浏览器之间的通信。
协商缓存机制下,浏览器要向服务器询问缓存的相关信息,判断是重新发起请求下载完整的响应,还是从本地获取缓存的资源。若服务端提示缓存资源未改动(Not Modified),资源会被重定向到浏览器缓存,对应状态码为304,过程如下图:
有两个字段:Last-Modified 和Etag
Last-Modified
是个时间戳。
若启用了协商缓存,会在首次请求时随着Response Headers返回,随后每次请求时,会带上一个叫If-Last-Modified的时间戳字段,值是上次返回的last-modified的值。服务器接收到这个时间戳后,,对比该时间戳和资源在服务器上的最后一次修改时间是否一致,从而判断资源是否发生了变化。若发生变化,则返回一个完整的相应内容,总更新Response Headers中的Last-Modified值;否则,返回上图的304
缺点:
(重复请求)手动改服务器内容,即使没修改内容,服务器也会认为是新内容,引发一次完整的响应;
(不请求)修改文件速度过快,,因为If-Modified-Since只能检查到以秒为单位的时间差,若感知不到,就不会请求。
----因此Etag解决了这个问题----
Etag
Etag是由服务器每个资源生成的唯一标识字符串,它基于文件内容编码,只要文件内容不同,对应的Etag就不同。
和Last-Modified类似,首次请求时会在响应头获取最初的标识字符串,下一次请求时,请求头会带上值相同,名为If-None-Match的字符串供服务端对比。
缺点:需要服务器额外付出开销,影响服务器的性能。
参考:全面总结浏览器缓存机制