2023-05-09 细解前端浏览器缓存

396 阅读7分钟

合理使用缓存,可以提高页面的打开速度,这句话是前端开发者耳熟能详的准则,但是缓存对页面性能有多大影响呢,下面从实验分析开始吧

缓存对页面性能的影响

这里随便打开一个网址,来测试有缓存和无缓存的两种情况对页面打开速度的影响

使用工具:Chrome DevTools + Lighthouse

1、无缓存测试

1、打开控制台,Network面板勾选Disable cache选项

disableCache.jpg

2、选择Lighthouse工具,点击Analyze page load 按钮

lightHouse.jpg

得到的性能报告如下:

nocache.jpg

2、有缓存测试

打开控制台,Network面板取消Disable cache选项,其他流程一样

disable.jpg

得到的性能报告如下:

cache.jpg

前后两次对比,有缓存时:

  • 白屏时间:缩短0.3s
  • 交互响应时间:缩短1.4s
  • 最大内容时间:缩短1.5s

通过实验证明,合理使用缓存确实可以提升页面的打开速度

什么是浏览器缓存

当我们访问一个网站时,会加载各种资源,如HTML文档、JS、CSS、图片等等。浏览器会将一些不经常变的资源保存在本地,这样下次访问相同网站时,就会直接从本地加载资源,并不通过请求服务器,这就是浏览器缓存

如何判断哪些资源是从缓存中获取的呢?

如下图Network的Size列:

memorycache.jpg

这里会看到两种标识:from memory cachefrom disk cache字样,这就说明该资源来自缓存,前者表示缓存来自内存,后者表示缓存来自硬盘,区别如下:

  • 1)memory cache表示缓存来自内存,disk cache表示缓存来自硬盘
  • 2)内存缓存比硬盘缓存更快,当tab页关闭后,内存缓存失效

一般情况下,浏览器会将js和图片等文件执行后直接存入内存中,这样刷新页面时,只需直接从内存中读取;而css文件则会存入硬盘中,所以每次渲染页面都要从硬盘中读取缓存

前端常用的缓存方案

强缓存和协商缓存相结合的方案

1)HTML文档配置协商缓存

2)JS、CSS、图片等资源配置强缓存

此方案的好处在于当项目版本更新时,可以获取最新的页面;若版本未变化,可继续复用之前的缓存资源;既很好的利用了浏览器缓存,又解决了页面版本更新的问题

浏览器的缓存流程

logo.jpg

这张图是经典的浏览器缓存流程,下面来说说具体的细节

强缓存

如果资源没有过期,就取缓存,如果过期了,则请求服务器,一般用于JS、CSS、图片等资源

如何判断强缓存过期?

response.jpg 第一次访问页面,浏览器会根据服务器返回的response Header来判断是否对资源进行缓存,如果响应头中有cache-controlexpires字段,代表该资源是强缓存

Cache-control

是HTTP1.1中控制网页缓存的字段,主要取值为:

  • public:资源客户端和服务器都可以缓存
  • private:资源只有客户端可以缓存
  • no-cache:客户端缓存资源,但是是否缓存需要经过协商缓存来验证
  • no-store:不使用缓存
  • max-age:缓存保质期,是相对时间

上图中HTTP响应头中cache-control为max-age=31536000表示这么多秒后该资源过期,如果未超过过期时间,浏览器会直接使用缓存结果,强制缓存生效

Cache-Control:no-store和no-cache的区别

cache-control:no-cache:这个值很容易让人误解,误以为响应不被缓存,实际上是会被缓存的,是协商缓存的标识,只不过每次都向服务器发起请求,来验证当前缓存的有效性

cache-control:no-store:这个才是响应不被缓存的意思

Expires

是HTTP1.0协议中的字段,值为一个时间戳,服务器返回该资源缓存的到期时间,但其有个缺点,就是它判断是否过期使用本地时间来判断的,本地时间是可以自己修改的

到了HTTP1.1协议已经被cache-control代替,使用max-age相对时间,解决了expires的缺陷

注意:当cache-control与expires都存在时,cache-control的优先级更高

协商缓存

浏览器携带缓存标识向服务器发送请求,服务器根据缓存标识来决定该资源是否过期,一般用于HTML资源,验证版本是否更新

触发条件:

  • cache-control的值为no-cache
  • cache-control的值max-age=0

协商缓存的标识

Last-Modified:文件在服务器最后被修改的时间,从服务器response header上获取

image.png

Last-Modified的验证流程:

1)第一次访问页面时,服务器的响应头会返回Last-modified字段

2)客户端再次发起该请求时,请求头if-modified-since字段会携带上次请求返回的last-modified值

3)服务器根据if-modified-since的值,与该资源在服务器最后被修改时间对比,若服务器上的时间大于Last-modified的值,则重新返回资源,返回200,表示资源已更新;反之则返回304,代表资源未更新,可继续使用缓存

image.png

Etag:当前资源文件的一个唯一标识(由服务器生成),若文件内容未发生变化该值就会改变

image.png

Etag的验证流程:

1)第一次访问页面时,服务器的响应头会返回etag字段

2)客户端再次发起该请求时,请求头if-None-Match字段会携带上次请求返回etag的值

3)服务器根据if-None-Match的值,与该资源在服务器的Etag值做对比,若值发生变化,状态码为200,表示资源已更新;反之则返回304,代表资源无更新,可继续使用缓存

请求的Request Headers携带if-None-Match字段:

image.png

为什么要有Etag?

Etag的出现主要是为了解决一些Last-modified难处理的问题:

1)一些文件也许会周期性的更改,但是内容并不改变(仅仅改变的修改时间),这时候并不希望客户端认为这个文件被修改了而重新去请求

2)某些文件修改非常频繁,比如在秒以下的时间内进行修改(比如1s内修改了N次),if-modified-since能检查到的粒度是秒级的,使用Etag就能够保证这种需求下客户端在1秒内能刷新N次cache

注意:Etag优先级高于Last-modified,若Etag与Last-modified两者同时存在,服务器优先校验Etag

协商缓存的两种状态

服务器根据请求头携带的缓存标识,判断该资源是否变化,资源未变化返回304,反之返回200

1)资源未变化,返回304

disk.jpg

2)若已更新,返回200

200.jpg

协商缓存的流程

1)第一次请求

客户端发送请求,服务器处理请求,返回文件内容和一堆Header,包括Etag和Last-modified,状态码为200

2)第二次请求

1、客户端发起请求,此时请求头上会带有if-None-Match值为Etagif-modified-since值为Last-modified

2、服务器优先判断Etag,若资源未变化状态码为304,客户端继续使用本地缓存;若资源发生变化,状态码为200并返回最新的资源