浏览器的缓存策略

缓存可以说是性能优化中简单高效的一种优化方式了。

一个优秀的缓存策略可以缩短网页请求资源的距离,减少延迟,并且由于缓存文件可以重复利用,还可以减少带宽,降低网络负荷。

对于一个数据请求来说,可以分为 网络请求后端处理浏览器响应 三个步骤。浏览器缓存可以帮助我们在第一和第三步骤中优化性能。

怎么实现缓存呢,缓存在哪?

  • service worker

 运行在浏览器背后的独立线程,一般可以用来实现缓存功能。传输协议必须是https,因为它有涉及到请求拦截,所以必须使用https来保障安全。service worker的缓存和浏览器其他内建的缓存机制不同,它可以让我们自由控制缓存哪些文件、如何匹配、如何读取缓存、并且缓存是持续性的。

说了那么多,都是理论上的介绍,那么在实际上面它如何实现缓存功能呢?

1. 先注册Service Worker

2. 监听到install事件以后就可以缓存需要的文件

3. 用户下次再访问就可以通过拦截请求的方式查询是否存在缓存,存在缓存就直接读取缓存文件,否则请求数据

  • memory cache

内存中的缓存,主要包含当前页面中已经抓取到的资源(比如:页面已经下载的样式、脚本、图片等)。读取内存中的数据肯定比磁盘快,内存缓存虽然读取高效,可是缓存持续性很短,会随着进程的释放而释放。就是我们关闭tab页面,内存中的缓存也就释放了。

那么这个时候有个问题,既然内存缓存很高效,我们是不是让数据都存放在内存中?

NO NO NO !!! 这个是万万不能的,计算机中的内存一定比硬盘容量小的多,操作系统需要精打细算内存的使用,所以能让我们使用的内存并不多。

当我们访问一个页面再次刷新页面,打开控制台发现很多数据都来自于内存缓存。

内存缓存中有一块重要的缓存资源是preloader相关指令下载的资源。(<link rel="prefetch">)众所周知 preloader 的相关指令已经是页面优化的常见手段之一,可以一边解析js/css文件,一边网络请求下一个资源。

但是要注意:内存缓存在缓存资源时并不关心返回资源的HTTP缓存头Cache-Control是什么值,并且不仅仅是只对url做匹配,还有Content-Type,CORS做校验。

  • disk cache
  • 存储在 硬盘中的缓存,读取速度慢点,但是什么都能存储在磁盘中,比之Memory Cache 胜在容量和存储时效性上。
  • 在所有的浏览器缓存上面 disk Cache 覆盖面基本是最大的。
  • 会根据 HTTP Header 中的字段判断哪些资源需要缓存,哪些资源可以不请求直接使用,哪些资源已经过期需要重新请求。
  • 并且即使在跨站点的情况下,相同地址的资源一旦被硬盘缓存下来,就不会再次去请求数据。绝大部分的缓存都来自disk Cache。
  • push cache

推送缓存,是HTTP/2中的内容,当以上三种缓存都没有命中时,它才会被使用。只在会话中存在,一旦会话结束就被释放,并且缓存时间也很短暂,在谷歌浏览器中只有5分钟左右,而且它并非严格执行HTTP请求头中的缓存指令。

如果以上四种缓存都没有命中的话就只能重新请求数据了。

看过以上四种缓存位置,产生了一个问题,浏览器会把哪些文件丢在内存中,哪些文件丢在硬盘中呢?

  • 对于大文件来说,大概率是不存储在内存中的
  • 当前系统内存使用率高的话,文件优先存储进硬盘。

缓存过程是怎样的呢?

浏览器与服务器的通信方式为应答模式。(浏览器发起请求 -> 服务器响应请求)

那么浏览器怎么确定这个资源该不该被缓存呢,如何去缓存?

浏览器第一次向服务端发起请求后拿到请求结果后,浏览器会将请求结果和缓存标识存入浏览器缓存中, 浏览器对于缓存的处理是根据第一次请求资源时返回的请求头来确定的。

总结:

  • 浏览器每次发起请求,都会先在浏览器缓存中查找有木有当前的请求结果和缓存标识。
  • 浏览器每次拿到请求结果都会将请求结果和缓存标识存放在浏览器缓存中。

什么是强缓存?

不会向服务器发送请求,直接从缓存中读取资源。可以在控制台Network选项看到该请求返回200状态码,并且size显示disk cache或者memory cache。

强缓存通过设置两种HTTP Header实现:Expires Cache-Control

  • Expires

          缓存过期时间。用来指定资源到期的时间。(在响应请求时告诉浏览器在过期时间前可以直接从缓存中存取数据,无需再次请求)

          注意:受限于本地时间,如果修改了本地时间,可能会造成缓存失效。

 

  • Cache-Control

          控制网页缓存。有多种指令可以使用。

指令解释
public表示响应可以被客户端和代理服务器缓存(所有内容都将被缓存)
private响应只能被客户端缓存(默认取值)
max-age=30缓存30秒后就过期,需要重新请求
s-maxage=30覆盖max-age,作用一样,只在代理服务器端有效
no-store不缓存任何响应
no-cache资源被缓存,但是立即失效,下次会发起请求验证资源是否过期
max-stale=3030秒内即使缓存过期,也使用该缓存
min-fresh=30希望在30秒内获取最新的响应

总结:

      强缓存判断是否缓存的依据来自于是否超出某个时间或者时间段,而不关心服务器端文件是否已经更新。这个可能会导致加载文件不是服务器端最新的内容。

什么是协商缓存?

协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存。

可以通过设置两种 HTTP Header 实现:Last-Modified ETag

  • Last-Modified && if-Modified-Since

          a. 浏览器第一次访问资源,服务器返回资源的同时,在response header中添加Last-Modified这个header (值为这个资源在服务器上的最后修改时间),浏览器接收缓存资源和header。

          b. 当再次请求这个资源,浏览器检测到有Last-Modified这个header,就会添加if-Modified-Since这个header,值为Last-Modified的值

          c. 服务器再次接收到这个资源请求,会根据if-Modified-Since的值与服务器中该资源的最后修改时间做对比

                  如果没有变化,返回304状态码和空的响应体,直接从缓存读取

                  如果小于服务器中该资源的最后修改时间,说明文件有修改,返回新的资源文件和200状态码

        但是Last-Modified也有缺点:

          如果本地打开缓存文件,即使没有对文件进行修改,也还是会造成Last-Modified的值被修改,服务端不能命中缓存导致发送相同的资源;

          因为Last-Modified只能以秒计时,如果在不可感知的时间内完成修改文件,那么服务端会认为资源还是没有修改,不会返回正确的资源。

 

  • ETag && if-None-Match

ETag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成)。只要资源有变化,ETag就会重新生成。

          浏览器在下一次加载资源向服务器发起请求会将上一次返回的ETag值放在request header里的if-None-Match,服务器只需要比对客户端传来的if-None-Match跟服务器上该资源的ETag是否一致,来判断服务端的资源是否更新。

                如果对上,直接返回304,知会客户端直接使用本地缓存

                如果有差异,将资源包括新的ETag重新发给客户端。

Last-Modified 和 ETag 有什么区别呢?

  • 精确度上:ETag 优于 Last-Modified
  • 性能上:Last-Modified 要优于 ETag,因为 Last-Modified 只需要记录时间,而 ETag 需要服务器通过算法来计算出一个hash值。
  • 优先级上:服务器校验优先考虑 ETag

缓存机制

「强制缓存」优先于「协商缓存」进行。

如果「强制缓存」生效,则直接使用缓存;如果不生效则进行「协商缓存」,「协商缓存」由服务器决定是否使用缓存。

如果「协商缓存」生效,则返回304,继续使用缓存;如果「协商缓存」失效,那么代表该请求的缓存失效,返回200,重新返回资源和缓存标识,再次存入浏览器缓存中。

如果什么缓存策略都没设置,浏览器会采用一个启发式的算法,通常会取响应头中的Date减去 Last-Modified 的值的10%作为缓存时间。

缓存在实际应用中有哪些场景呢?

  • 频繁变动的资源

使浏览器每次都请求服务器,然后配合 ETag 或者 Last-Modified 来判断资源是否有效。虽然不能节省请求数量,但是能显著减少响应数据大小。

Cache-Control: no-cache
  • 不常变动的资源

给它们的Cache-Control配置一个很大的 max-age=31536000(一年),这样浏览器之后请求相同的url会命中强制缓存。

为了解决更新问题,需要在文件名或者路径中添加hash,版本号等动态字符,从而达到更改引用url的目的,让之前的强制缓存失效。(jquery.3.3.3.min.js、lodash.min.js都采用这个模式)

Cache-Control: max-age=31536000

用户操作对于缓存有什么影响呢?

打开网页,地址栏输入地址:查找disk cache中是否有匹配,如果有则使用,没有则发送请求

普通刷新(F5):因为tab并没有关闭,因此memory cache是可用的,会被优先使用,其次才是 disk cache

强制刷新(Ctrl+F5):浏览器不使用缓存,因此发送的请求头均带有 Cache-Control: no-cache (Pragma: no-cache 为了处理兼容),服务器直接返回200和最新内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值