聊聊浏览器缓存

前言

最近宅在家学习了一下缓存知识,总结成文档,和你们交流分享。说到缓存,有浏览器缓存、数据库缓存、代理服务器缓存、CDN缓存等,咱们今天只聊浏览器缓存(其余的涉及到个人知识盲区)。css

不少文章中提到的前端缓存、web缓存也都是浏览器缓存。前端

缓存位置

咱们都知道,浏览器请求时会先看看有没有缓存,命中缓存就直接拿到资源,不用再去向服务器请求。省去了请求的时间,也减轻了服务器的压力。那么缓存都是放在哪里的呢?git

  1. Service Worker
  2. Memory Cache
  3. Disk Cache
  4. Push Cache

缓存的四个位置按照优先级顺序依次为Service Worker、Memory Cache、Disk Cache和Push Cache。github

Service Worker

Service Worker能够理解成浏览器和服务器之间的一个代理,比起Memory Cache 或是Disk Cache,Service Worker可让咱们开发者来控制缓存哪些文件、如何匹配缓存、如何读取等。出于安全考量,Service Worker只能用HTTPS来承载。web

若是Service Worker没有命中缓存,那么就会用fetch() 函数来获取数据。这里须要注意的是:通过fetch()方法获取的资源,不管是从Memory Cache中拿到的数据仍是网络请求拿到的,都会显示从Service Worker中拿的。 像这样:算法

Memory Cache

Memory Cache就是浏览器放在内存中的缓存,内存咱们都知道:容量小,可是读取速度快,因此一些小的资源就能够在内存中缓存了。数据库

打开一个网页,打开控制台,刷新一次,就能够看到有的资源是从Memory Cache中拿到的。如图: 浏览器

图中看到Time那一栏的值,都是0ms(这里是特例,不全都是0ms),能够看到从内存中拿资源是很是快的,可是内存的容量比较小,时效性也比较低,Tab页关掉,这些缓存就会失效了。缓存

Memory Cache里面主要是图片、js 、css文件,preload 预加载来的资源也会放在Memory Cache中。Memory Cache是不关心http首部字段的。设置的max-age或是no-cache都会被浏览器忽略掉。安全

Disk Cache

真正关心http首部字段的人是Disk Cache,就是硬盘中的缓存。硬盘与上面的内存是互补的,硬盘容量大,时效性长(资源过时时间长),缺点就是读取速度慢。

Disk Cache会根据HTTP请求的响应头来判断哪些资源能够缓存、哪些资源过时了须要从新请求等。即便是不如内存的速度快,可是省去了网络请求的话,速度也仍是提高了很多的。绝大部分的缓存都是来自于Disk Cache。

硬盘上的缓存,若是两个站点共用了一张图,是能够共用的。

Push Cache

Push Cache 就是HTTP2的服务器端推送。是服务器端推测咱们可能须要的一些资源,提早推送到客户端的缓存里面来,等到客户端须要,直接从缓存里面拿就能够了。

例如,咱们请求一个HTML,那么确定须要这个页面的图片、css、js资源了,服务器端能够提早推送。

好了,咱们如今来梳理一下整个流程:

  1. Service Worker,命中缓存,返回资源;不然调用fetch方法
  2. 查看Memory Cache,命中缓存,返回资源;不然到第3步
  3. 查看Disk Cache,命中缓存,返回资源,不然到第4步
  4. 查看Push Cache
  5. 没有命中缓存,进行网络请求
  6. 把响应内容存到Disk Cache
  7. 把响应内容的引用存到memory cache
  8. 把响应内容存入Service Worker

强缓存 & 协商缓存

前面说完了缓存的位置,下面咱们聊聊缓存的两种方式:强缓存和协商缓存。

强缓存

强缓存就是服务器端返回响应的时候,告诉客户端多长时间这个资源不失效,直接用就好了,不用来问我。

强缓存主要是用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有不少可选的值,咱们说几个经常使用的。(查看所有值

  • no-store,不容许缓存,每次请求都必须从源服务器请求资源
  • no-cache,能够缓存,可是每次得先去服务器确认是否过时
  • public,代理服务器和客户端均可以缓存
  • private,只有客户端能够缓存
  • s-maxage,和max-age含义同样,可是只对代理服务器有效

协商缓存

若是能次次都命中强缓存那固然很好,省了网络请求,网页的响应速度那绝对的快。可是若是服务器上的资源更新了呢?那完蛋,咱们就拿到脏数据了。

因此协商缓存就要起做用了。协商缓存就是客户端虽然缓存了,可是客户端仍是得发请求到服务器去确认一下,资源过时没?没-> 304,拿缓存;过时了,200,返回响应内容。

协商缓存的两个首部字段是:ETag和Last-Modified。准确地说是两对儿:ETag & If-None-Match ;Last-Modified & If-Modified-Since。

ETag

ETag 是服务器端产生的一个hash字符串,用来标识一个资源的状态。像这样:

ETag: "82e222983df93"

服务器会为每份资源分配对应的ETag,资源更新时,ETag也会更新。ETag的生成并无什么统一的算法规则,看服务器怎么生成了。

画个图吧。客户端带过去的If-None-Match就是服务器端返回的ETag,服务器端会把If-None-Match的值和存在服务器端的ETag值对比,一致则说明资源没更新,不然,更新了。

Last-Modified

Last-Modified: Thu, 10 Nov 2017 08:46:12 GMT

Last-Modified是服务器告诉咱们资源最后修改的时间。仍是上个图吧,简单又清晰。

Last-Modified相比于ETag,缺点在于:

  1. Last-Modified只能精确到秒,若是1秒内,资源改了两次,那就出事了。
  2. 资源的最后修改时间改了,可是内容没改,Last-Modified仍是会算做资源被修改了,而ETag不会。

缓存策略应用

目前的项目大多使用这种缓存方案的:

  • HTML: 协商缓存;
  • css、js、图片:强缓存,文件名带上hash。

浏览器行为

  • 地址栏输入网址:查找Disk Cache,命中缓存,拿到资源,不然发起网络请求。
  • 刷新网页:先查看Memory Cache,没有命中缓存的话再去Disk Cache。
  • 强制刷新:不使用缓存,去服务器请求。

以上,若有错漏,恳请指正!

参考文章

相关文章
相关标签/搜索