缓存初探

缓存是浏览器性能优化中非常重要的一种方式,我们可知数据请求可以分为:发起请求、后端处理、浏览器响应三个步骤。而前端缓存主要是在“请求”和“响应”中进行。在请求步骤中,浏览器使用缓存就可以不用发送请求,从而减少请求次数;在响应步骤中,如果前后端数据一致,那么数据就无须再从后端传到前端,通过减少响应的内容从而减少传输时间。

附一张我感觉是超级无敌专业的思维导图:

一、缓存位置及分类

优先级由上至下:

  Service worker

  memory cache

  disk cache

 

Service worker:是浏览器在后台独立于网页运行的脚本,类似于一个中间人,浏览器发出的请求都会被Service Worker拦截并被它处理。当有Service Worker时,浏览器会优先从Service Worker读取缓存。

 

memory cache是短期存储,页面刷新时(普通刷新,F5)通常是从内存中获取缓存;页面关闭,缓存就失效了,从内存中获取缓存比从硬盘中获取速度快。几乎所有的请求资源都能进入memory cache。浏览器为了加快读取缓存速度而进行的自身的优化行为,不受开发者控制也不受HTTP协议的约束。

从memory cache获取缓存内容时,浏览器会忽视max-age=0,no-cache等头部配置,如果完全不想让一个资源进入缓存,需要使用no-store。

 

disk cache是存在硬盘中的缓存,当页面关闭后再次打开时读取的就是硬盘缓存。

disk cache(HTTP cache)包括强制缓存(强缓存)和协商缓存(对比缓存):首先进行强制缓存,如果强缓存失效,需要使用对比缓存,由服务器决定缓存内容是否失效。

强制缓存:

当命中强制缓存时,浏览器不会去请求服务器,而是直接使用本地缓存资源,从Chrome开发者工具的Network可以看到返回200状态码,size一栏显示from memory cache或from disk cache。

  从Network —> size一栏可以看到两类:

  • 如果是显示数字,几k或者几M,则是表示是从网络传输的
  • 其他的则是from ServiceWorker,from memory cache,from disk cache

强制缓存直接减少请求数,是提升最大的缓存策略

是否命中强制缓存是由头中的expirescache-control控制的,通过HTTP Header设置Expires和Cache-Control

1、 expires是HTTP1.0时的标准,是表示服务器的过期时间,是格林威治时间,绝对时间。当请求的时候客户端的时间超过expires标识的时间时就会去请求服务器。

2、  但是expires存在的问题是:当用户手动修改了这个时间就会有问题

3、  Cache-control是HTTP1.1的产物,可以看作expires的补充

4、 判断缓存是否过期的步骤:看是否有cache-control的max-age;如果没有则用expires作为过期时间比较

Cache-control常用值:

  • Max-age:缓存的最大有效时间,会覆盖expires。
  • S-maxage:如果该值存在,则会优先使用它作为CDN的缓存时间
  • Public:表明响应可以被任何对象包括客户端、服务器缓存
  • Private:只能是发起请求的浏览器进行缓存
  • No-cache:仍然对资源使用缓存,每一次在使用缓存之前必须向服务器对缓存资源进行验证,确认数据是否和服务器保持一致,实际上是需要进行协商缓存来验证决定是否需要缓存,表示不适用cache-control的方式左前置验证,二是使用ETag或者Last-Modified字段来控制缓存
  • No-store:所有内容都不会被缓存,即不使用强制缓存也不使用协商缓存
  • Must-revalidate:如果配置了max-age,如果超过max-age的时间,即需要对资源的有效性进行验证

  

补充一下~max-age=0和no-cache在浏览器反应上是没有差别的,两者的区别在于:

max-age=0在语义上被理解为:到期应该(should)重新验证

no-cache:必须(must)重新验证

 

协商缓存:

强制缓存失效后,浏览器需要携带缓存标识与服务器协商是否使用缓存,有两种情况:

  • 命中协商缓存,返回304状态码:

  

  • 缓存失效,返回200状态码:

  

协商缓存由响应头中的Last-Modified和ETag + 请求头中的If-Modified-Since和If-None-Match控制

优化点在于:响应体积上的节省,通过减少响应体体积来缩短网络传输时间。对比缓存在请求数上和没有缓存是一样的,但是如果是304返回的仅仅是一个状态码,没有实际的内容

 

Response:Last-Modified + Request:If-Modified-Since

浏览器第一次访问资源时,服务器在返回资源的同时,同时传回Last-Modified这个数据告诉浏览器资源最后一次被修改的时间,浏览器将这个Last-Modified值和资源存到缓存数据库中;

当下次浏览器再次请求相同的资源时会检测到有Last-Modified这个header,于是将这个Last-Modified值写入到If-Modified-Since中传回服务器,服务器通过对比Last-Modified和If-Modified-Since两个值是否一致,如果一致就返回空响应体和304状态码,表示资源未被修改,直接从缓存中拉取资源;如果两个值不一致说明服务器中该资源被更新,则返回200和新的资源

Last-Modified的弊端:只能以秒记,如果处理文件在不可感知的时间内完成服务器还是会以为资源命中;如果本地打开缓存文件即使不修改也会改变Last-Modified值。

 

Response:ETag + Request:If-None-Match

整个流程同(Response:Last-Modified + Request:If-Modified-Since)只不过ETag是文件的特殊标识,由服务器生成,只要资源有变化,ETag就会重新生成。

 

两组数据对比:

ETag的优先级高于Last-Modified,即服务器也会优先验证If-None-Match;

在性能上ETag是逊于Last-Modified的

 

补充一个 CDN缓存:

CDN(Content Delivery Network)内容分发网络

采取与强制缓存相似的机制,把CDN看成是浏览器,把源服务器看成是浏览器需要请求的服务器,此时,源服务器的max-age头决定了资源在CDN节点本地缓存的时间,如果s-maxage存在,则会优先使用s-maxage

二、实际场景应用缓存

  • 不经常更新的资源:

  一般会设置一个很大的值,例如:Cache-Control: max-age=3453600,表示在3453600ms内再次加载资源就会命中强缓存。 

  • 频繁变动的资源:

  首先需要设置:Cache-Control: no-cache 使得浏览器每次都请求服务器,然后配合ETag和Last-Modified来验证资源是否有效。

参考文章:

一文读懂前端缓存

扒一扒浏览器缓存机制

深入理解浏览器的缓存机制

 

原文地址:https://www.cnblogs.com/ningyn0712/p/11929408.html