1.前言缓存可以说是性能优化中一种简单高效的优化方法。优秀的缓存策略可以缩短网页请求资源的距离,减少延迟,并且由于缓存文件可以重复使用,还可以降低带宽和网络负载。对于一个数据请求,可以分为三个步骤:发起网络请求、后端处理、浏览器响应。浏览器缓存可以帮助我们优化第一步和第三步的性能。比如你不发起请求直接使用缓存,或者发起请求但是后台保存的数据和前端是一致的,那么就不需要回传数据,减少了响应数据。在接下来的内容中,我们将通过缓存位置、缓存策略和实际场景应用的缓存策略来探讨浏览器的缓存机制。2、缓存位置从缓存位置分为四种,每种都有优先级。当依次查找缓存都没有命中时,就会请求网络。ServiceWorkerMemoryCacheDiskCachePushCache1.ServiceWorkerServiceWorker是运行在浏览器后面的独立线程,一般可以用来实现缓存功能。使用ServiceWorker时,传输协议必须是HTTPS。因为ServiceWorker中涉及到请求拦截,所以必须使用HTTPS协议来保证安全。ServiceWorker的缓存不同于浏览器内置的其他缓存机制。它可以让我们自由控制缓存哪些文件,如何匹配缓存,如何读取缓存,缓存是持久化的。ServiceWorker的缓存功能一般分为三步:首先需要先注册ServiceWorker,然后在监听install事件后缓存需要的文件,然后可以通过拦截下次用户访问时请求,如果有缓存,则直接读取缓存文件,否则,请求数据。当ServiceWorker没有命中缓存时,我们需要调用fetch函数来获取数据。也就是说如果我们在ServiceWorker中没有命中缓存,我们会按照缓存查找优先级来查找数据。但是无论我们是从MemoryCache中获取数据还是从网络请求中获取数据,浏览器都会显示我们从ServiceWorker中获取的内容。2.MemoryCacheMemoryCache也就是内存中的缓存,主要包括当前页面已经抓取的资源,比如页面已经下载的样式、脚本、图片等。读取内存中的数据肯定比磁盘快。内存缓存虽然读取效率高,但是缓存持续时间很短,会随着进程的释放而释放。一旦我们关闭Tab页面,内存中的缓存就被释放了。那么既然内存缓存这么高效,我们能不能把所有的数据都放在内存中呢?这是不可能的。电脑中的内存肯定比硬盘的容量小很多,操作系统需要仔细规划内存的使用,所以我们能使用的内存一定不会多。当我们访问页面,再次刷新页面时,可以发现有很多数据来自于内存缓存。内存缓存中一个重要的缓存资源是preloader相关指令(如)下载的资源。众所周知,预加载器的相关指令已经是页面优化的常用手段之一。它可以在从网络请求下一个资源的同时解析js/css文件。需要注意的是,内存缓存在缓存资源时并不关心返回的HTTP缓存头Cache-Control的值。同时,资源匹配不仅仅是为了URL匹配,还有Content-Type、CORS等特征进行校验。3.DiskCacheDiskCache也就是存储在硬盘中的缓存。读取速度较慢,但??一切都可以存储在磁盘上。与MemoryCache相比,在容量和存储时效性上更胜一筹。在所有的浏览器缓存中,DiskCache的覆盖范围基本上是最大的。它会根据HTTPHerder中的字段判断哪些资源需要缓存,哪些资源可以不用请求直接使用,哪些资源已经过期需要重新请求。并且即使在跨站的情况下,一旦相同地址的资源被硬盘缓存,就不会再请求数据了。大多数缓存来自磁盘缓存。下面我们将详细介绍HTTP协议头中的缓存字段。浏览器将哪些文件放入内存?哪些进入硬盘?关于这一点,网上众说纷纭,不过下面这个观点比较靠谱:对于大文件,大概率是不会存入内存的。反之,如果当前系统内存占用率高,则文件会优先存储在硬盘中。4.PushCachePushCache(推送缓存)就是HTTP/2中的内容。当上面三个缓存都没有命中时才会使用。它只存在于会话(Session)中,一旦会话结束即被释放,而且缓存时间也很短,在Chrome浏览器中只有5分钟左右,并且没有严格执行HTTP头中的缓存指令。PushCache在国内能找到的资料很少,这也是因为HTTP/2在国内还不够普及。在这里我推荐阅读JakeArchibald的文章HTTP/2pushistougherthanIthoughtIthought。文中的几个结论:所有资源都可以推送和缓存,但是Edge和Safari浏览器支持比较差。Pushno-cache和no-store资源一旦连接关闭,PushCache就会被释放。多个页面可以使用相同的HTTP/2连接,因此它们可以使用相同的PushCache。这主要取决于浏览器的实现。出于性能的考虑,有些浏览器会对同一个域名但不同的tab标签使用同一个HTTP连接。PushCache中的缓存只能使用一次。浏览器可以拒绝接受现有的资源推送。您可以将资源推送到其他域名。如果以上四种缓存都没有命中,只能发起请求获取资源。出于性能考虑,大多数接口应该选择好的缓存策略。一般浏览器的缓存策略分为强缓存和协商缓存两种,缓存策略是通过设置HTTPHeaders来实现的。这里推荐一个前端开发交流圈:1007317281,里面整理了大量的学习资料,都是干货,总结了移动应用网站开发,css,html,webpack,vuenodeangular,面试资源。送给每一位大数据小伙伴,让自学更轻松。这里不仅是小白的聚集地,还有大牛在线解答!欢迎新手和进阶的小伙伴进群学习交流,共同进步!3、缓存过程分析浏览器与服务器通信的方式是响应模式,即:浏览器发起HTTP请求——服务器响应请求,那么浏览器是如何判断一个资源是否应该被缓存的,又是如何判断的呢?缓存它?浏览器第一次向服务器发起请求并得到请求结果后,将请求结果和缓存标识保存在浏览器缓存中。浏览器对缓存的处理是根据第一次请求资源时返回的响应头来决定的。.具体过程如下图所示:从上图我们可以知道,浏览器每次发起请求,都会先在浏览器缓存中查找请求的结果和缓存标识以上两个结论是浏览器缓存机制的关键。它保证了每个请求的缓存存储和读取。只要了解浏览器缓存的使用规律,一切问题迎刃而解。是的,本文也将围绕这一点进行详细的分析。为了方便大家理解,这里我们根据是否需要向服务器重新发起HTTP请求,将缓存过程分为两部分,即强缓存和协商缓存。4、强缓存强缓存:不会向服务器发送请求,而是直接从缓存中读取资源。在chrome控制台的Network选项中,可以看到请求返回状态码为200,Size显示fromdiskcache或frommemorycache。可以通过设置两个HTTPHeaders来实现强缓存:Expires和Cache-Control。1.Expires缓存过期时间,用于指定资源过期的时间,是服务器端的具体时间点。也就是说,Expires=max-age+请求时间需要和Last-modified结合使用。Expires是Web服务器的响应头域。在响应http请求时,告诉浏览器在过期时间之前,浏览器可以直接从浏览器缓存中取数据,不需要再次请求。Expires是HTTP/1的产物,受本地时间限制。如果本地时间被修改,缓存可能会失效。Expires:Wed,22Oct201808:41:00GMT表示该资源将在Wed,22Oct2208:41:00GMT之后过期,需要再次请求。2.Cache-Control在HTTP/1.1中,Cache-Control是最重要的规则,主要用来控制网页缓存。例如当Cache-Control:max-age=300时,表示在请求正确返回时间5分钟内再次加载资源(浏览器也会记录),强缓存命中.Cache-Control可以在请求头或响应头中设置,可以组合多个指令:public:所有内容都会被缓存(客户端和代理服务器都可以缓存)。具体来说,response可以被任意一个中间节点缓存,比如Browser<--proxy1<--proxy2<--Server,中间proxy可以缓存资源,比如下次请求同样的资源proxy1直接把缓存的东西给浏览器不再询问proxy2。private:所有内容只能被客户端缓存,默认值Cache-Control。具体来说就是中间节点不允许缓存。对于Browser<--proxy1<--proxy2<--Server,proxy会老老实实把server返回的数据发送给proxy1,它不会缓存任何数据。当浏览器下次再次请求时,代理会做好转发请求的工作,而不是自己对缓存的数据进行认领。no-cache:客户端缓存内容。是否使用缓存需要通过协商缓存来验证。表示不使用Cache-Control的缓存控制方式进行预验证,而是使用Etag或Last-Modified字段来控制缓存。需要注意的是,no-cache这个名字有点误导。设置no-cache后,并不代表浏览器不再缓存数据,而是浏览器在使用缓存数据时,需要确认数据是否仍然与服务器保持一致。no-store:不缓存所有内容,即不使用强制缓存和协商缓存。max-age:max-age=xxx(xxx为数字)表示缓存内容在xxx秒后过期代理服务器(如CDN缓存)。比如当s-maxage=60时,在这60秒内,即使CDN的内容有更新,浏览器也不会发起请求。max-age用于普通缓存,s-maxage用于代理缓存。s-maxage的优先级高于max-age。如果s-maxage存在,它将覆盖max-age和Expires标头。max-stale:可以容忍的最大陈旧时间。max-stale指令表示客户端愿意接受过时的响应。如果指定max-stale的值,则最大容忍时间为对应的秒数。如果不指定,则表示浏览器愿意接收任何年龄响应(年龄是指响应产生或被源站确认的时间与当前时间的差值)。min-fresh:可以容忍的最低新鲜度。min-fresh表示客户端不愿意接受新鲜度不超过当前年龄加上min-fresh设置的时间之和的响应。从图中我们可以看出,我们可以将多条指令一起使用,达到多种目的。比如我们希望资源可以缓存,客户端和代理服务器都可以缓存,可以设置缓存过期时间等。3.Expires和Cache-Control的比较其实没有太多两者之间的区别。不同的是Expires是http1.0的产物,Cache-Control是http1.1的产物。如果两者同时存在,Cache-Control优先级高于Expires;在某些不支持HTTP1.1的环境中,Expires将发挥作用。所以Expires其实是一个过时的产物,现阶段它的存在只是为了兼容性的一种写法。强缓存判断是否缓存的依据来自于是否超过某个时间或者某个时间段,不管服务端文件是否更新过,这可能会导致加载的文件不是最新的内容服务器端,那么我们怎么知道服务器端的内容是否已经发生了更新呢?此时我们需要使用协商的缓存策略。5、协商缓存协商缓存是强制缓存失效的过程,浏览器向服务器发送带有缓存标识的请求,服务器根据缓存标识决定是否使用缓存。主要有两种情况:协商缓存生效,返回304和NotModified;协商缓存失效,返回200,请求结果协商缓存可以通过设置两个HTTPHeaders:Last-Modified和ETag来实现。1、Last-Modified和If-Modified-Since浏览器第一次访问资源时,服务器返回资源时,在响应头中加入Last-Modified头。该值是服务器上资源的最后修改时间。浏览器接收到文件和头部后缓存;Last-Modified:Fri,22Jul201601:47:00GMT下次浏览器请求这个资源时,浏览器检测到有Last-Modifiedheader,于是添加了If-Modified-Since,这个header的值为Last-Modified中的值;服务器再次收到该资源请求时,会将If-Modified-Since中的值与该资源在服务器中的最后修改时间进行比较。如果没有变化,则返回304和empty直接从缓存中读取响应体。如果If-Modified-Since的时间小于这个资源在服务器上的最后修改时间,说明文件已经更新,所以返回新的资源文件和200,但是Last-Modified有一些缺点:如果本地打开缓存文件,即使文件没有被修改,仍然会导致Last-Modified被修改,服务端无法命中缓存并发送相同的资源,因为Last-Modified只能以秒计,如果修改在一个不可察觉的时间文件内完成,服务器会认为该资源仍然命中,不会返回正确的资源。既然根据文件修改时间来判断是否缓存还不够,那么是否可以直接根据文件内容是否修改来判断缓存策略呢?因此在HTTP/1.1中出现了ETag和If-None-Match。ETag和If-None-MatchEtag是服务器响应请求时返回当前资源文件的唯一标识(由服务器生成)。只要资源发生变化,Etag就会重新生成。浏览器下次加载资源向服务器发送请求时,会将上次返回的Etag值放入请求头中的If-None-Match中,服务器只需要比对发送的If-None-Match即可通过客户端与自己服务器端资源在网上的ETag是否一致,可以判断该资源相对于客户端是否被修改过。如果服务端发现ETag不匹配,则直接将新资源(包括新的ETag)以常规GET200返回包的形式发送给客户端;如果ETag一致,则直接返回304,告知客户端直接使用本地缓存即可。3、两者比较:首先,在准确率上,Etag优于Last-Modified。Last-Modified的时间单位是秒。如果一个文件在1秒内被多次更改,那么他们的Last-Modified实际上并不能反映修改,但Etag每次都会更改以确保准确性;如果是负载均衡的Server,各个server产生的Last-Modified也可能不一致。其次,在性能上,Etag不如Last-Modified。毕竟Last-Modified只需要记录时间,而Etag则需要服务器通过算法计算出一个hash值。第三,在优先级上,服务器验证优先考虑Etag。六、缓存机制强制缓存优先于协商缓存。如果强制缓存(Expires和Cache-Control)生效,则直接使用缓存。如果不生效,协商缓存(Last-Modified/If-Modified-SinceandEtag/If-None-Match),协商缓存由服务器决定是否使用缓存,如果协商缓存无效,表示请求的缓存无效,返回200,并再次返回资源和缓存ID,然后存入浏览器缓存;如果生效,则返回304,继续使用缓存。具体流程图如下:看到这里,不知道大家有没有这样的疑问:如果不设置缓存策略,浏览器会怎么做?在这种情况下,浏览器会使用启发式算法,通常取响应头中的Date减去Last-Modified值的10%作为缓存时间。七、缓存策略在实际场景中的应用1、频繁变化的资源Cache-Control:no-cache对于频繁变化的资源,首先需要使用Cache-Control:no-cache让浏览器每次都请求服务器,然后配合ETag或Last-Modified验证资源是否有效。虽然这种方法不能节省请求的数量,但它可以显着减少响应数据的大小。2.不经常变化的资源的Cache-Control:max-age=31536000通常在处理这类资源时,为其Cache-Control(一年)配置一个较大的max-age=31536000,以便后续浏览器对相同URL的请求将命中强制缓存。为了解决更新问题,需要在文件名(或路径)中加入hash、版本号等动态字符,然后改变动态字符,达到改变引用URL的目的,使之前的强制失效缓存(事实上,它不是立即失败,只是不再使用)。网上提供的类库(如jquery-3.3.1.min.js、lodash.min.js等)都采用这种模式。8、用户行为对浏览器缓存的影响所谓用户行为对浏览器缓存的影响,是指用户操作浏览器时会触发什么样的缓存策略。主要有三种:打开网页,在地址栏输入地址:查找磁盘缓存中是否有匹配。可用时使用;如果没有,发送网络请求。正常刷新(F5):因为TAB没有关闭,所以内存缓存可用,会优先使用(如果匹配)。第二个是磁盘缓存。强制刷新(Ctrl+F5):浏览器不使用缓存,所以发送的请求头都有Cache-control:no-cache(为了兼容,Pragma:no-cache也包括在内),服务器直接返回200和最新内容。结束语感谢大家的观看,如有不足,欢迎批评指正。获取信息???这次给大家推荐一个免费学习群,里面总结了移动应用网站开发,css,html,webpack,vuenodeangular,面试资源。欢迎对web开发技术感兴趣的同学加入Q群:???1007317281???,不管你是小白还是大牛,我都欢迎你,还有整理了一套高效的学习路线和教程大牛分享给大家免费分享,每天更新视频信息。最后祝大家早日学业有成,拿到满意的offer,快速升职加薪,走上人生巅峰。