最近宅在家学习了一下缓存知识,总结成文档,和你们交流分享。说到缓存,有浏览器缓存、数据库缓存、代理服务器缓存、CDN缓存等,咱们今天只聊浏览器缓存(其余的涉及到个人知识盲区)。css
不少文章中提到的前端缓存、web缓存也都是浏览器缓存。前端
咱们都知道,浏览器请求时会先看看有没有缓存,命中缓存就直接拿到资源,不用再去向服务器请求。省去了请求的时间,也减轻了服务器的压力。那么缓存都是放在哪里的呢?git
缓存的四个位置按照优先级顺序依次为Service Worker、Memory Cache、Disk Cache和Push Cache。github
Service Worker能够理解成浏览器和服务器之间的一个代理,比起Memory Cache 或是Disk Cache,Service Worker可让咱们开发者来控制缓存哪些文件、如何匹配缓存、如何读取等。出于安全考量,Service Worker只能用HTTPS来承载。web
若是Service Worker没有命中缓存,那么就会用fetch()
函数来获取数据。这里须要注意的是:通过fetch()
方法获取的资源,不管是从Memory Cache中拿到的数据仍是网络请求拿到的,都会显示从Service Worker
中拿的。 像这样:算法
Memory Cache就是浏览器放在内存中的缓存,内存咱们都知道:容量小,可是读取速度快,因此一些小的资源就能够在内存中缓存了。数据库
打开一个网页,打开控制台,刷新一次,就能够看到有的资源是从Memory Cache中拿到的。如图: 浏览器
图中看到Time那一栏的值,都是0ms(这里是特例,不全都是0ms),能够看到从内存中拿资源是很是快的,可是内存的容量比较小,时效性也比较低,Tab页关掉,这些缓存就会失效了。缓存
Memory Cache里面主要是图片、js 、css文件,preload 预加载来的资源也会放在Memory Cache中。Memory Cache是不关心http首部字段的。设置的max-age
或是no-cache
都会被浏览器忽略掉。安全
真正关心http首部字段的人是Disk Cache,就是硬盘中的缓存。硬盘与上面的内存是互补的,硬盘容量大,时效性长(资源过时时间长),缺点就是读取速度慢。
Disk Cache会根据HTTP请求的响应头来判断哪些资源能够缓存、哪些资源过时了须要从新请求等。即便是不如内存的速度快,可是省去了网络请求的话,速度也仍是提高了很多的。绝大部分的缓存都是来自于Disk Cache。
硬盘上的缓存,若是两个站点共用了一张图,是能够共用的。
Push Cache 就是HTTP2的服务器端推送。是服务器端推测咱们可能须要的一些资源,提早推送到客户端的缓存里面来,等到客户端须要,直接从缓存里面拿就能够了。
例如,咱们请求一个HTML,那么确定须要这个页面的图片、css、js资源了,服务器端能够提早推送。
好了,咱们如今来梳理一下整个流程:
fetch
方法前面说完了缓存的位置,下面咱们聊聊缓存的两种方式:强缓存和协商缓存。
强缓存就是服务器端返回响应的时候,告诉客户端多长时间这个资源不失效,直接用就好了,不用来问我。
强缓存主要是用Cache-Control和Expires这两个首部字段来控制。
Expires字段的值是资源的失效时间。像这样:
Thu, 10 Nov 2017 08:46:12 GMT
这个字段的缺陷在于,客户端的时间能够用户手动改掉,致使缓存失效。他是http 1.0的字段,目前基本上不会用了,用到只是为了兼容。你们了解一下就好。max-age的优先级比Expires高。
Cache-Control的max-age字段(单位:秒)能够设置资源在多少秒以后过时。像这样:
Cache-Control:max-age=500
表示500s内这个资源都无须向服务器确认,浏览器再次请求会直接命中缓存,使用缓存就行了。
Cache-Control有不少可选的值,咱们说几个经常使用的。(查看所有值)
若是能次次都命中强缓存那固然很好,省了网络请求,网页的响应速度那绝对的快。可是若是服务器上的资源更新了呢?那完蛋,咱们就拿到脏数据了。
因此协商缓存就要起做用了。协商缓存就是客户端虽然缓存了,可是客户端仍是得发请求到服务器去确认一下,资源过时没?没-> 304,拿缓存;过时了,200,返回响应内容。
协商缓存的两个首部字段是:ETag和Last-Modified。准确地说是两对儿:ETag & If-None-Match ;Last-Modified & If-Modified-Since。
ETag 是服务器端产生的一个hash字符串,用来标识一个资源的状态。像这样:
ETag: "82e222983df93"
服务器会为每份资源分配对应的ETag,资源更新时,ETag也会更新。ETag的生成并无什么统一的算法规则,看服务器怎么生成了。
画个图吧。客户端带过去的If-None-Match就是服务器端返回的ETag,服务器端会把If-None-Match的值和存在服务器端的ETag值对比,一致则说明资源没更新,不然,更新了。
Last-Modified: Thu, 10 Nov 2017 08:46:12 GMT
Last-Modified是服务器告诉咱们资源最后修改的时间。仍是上个图吧,简单又清晰。
Last-Modified相比于ETag,缺点在于:
目前的项目大多使用这种缓存方案的:
以上,若有错漏,恳请指正!