浏览器缓存

缓存对于前端性能优化来说是个很重要的点,良好的缓存策略可以降低资源的重复加载提高网页的整体加载速度。

简单来说,浏览器缓存就是把一个已经请求过的资源拷贝一份存储起来,当下次需要该资源时,浏览器会根据缓存机制决定直接使用缓存资源还是再次向服务器发送请求

浏览器中大多资源都是从浏览器直接读取了缓存

浏览器中大多资源都是从浏览器直接读取了缓存

缓存位置

浏览器的缓存位置有以下四个,优先级排列从高到低如下:

Servive Worker

Memory Cache

Disk Cache

Push Cache

当上述四个缓存位置中均无所想要请求资源时则会向服务器发起请求

  • Service Worker:是一个注册在指定源和路径瞎的事件驱动worker。它采用JavaScript控制关联的页面或者网站,拦截并修改访问和资源请求,细粒度地缓存资源(Application -> Service Worker
  • Memory Cache:内存中的缓存。容量小、读取高效、持续性短,随着进程的释放而释放
  • Disk Cache:磁盘中的缓存。容量大、读取缓慢、持续性长,任何资源都能存储到磁盘中
  • Push Cache:HTTP/2.0 中的内容,缓存时间短暂,只在Session中存在,会话结束就被释放。

缓存策略

浏览器每次向服务器发起 HTTP 请求获得资源后都会根据不同情况(代码控制 / 请求头表示字段等)将资源缓存起来。

其中,根据相应的 HTTP Header 将其分为强制缓存协商缓存

强制缓存

强制缓存就是想浏览器缓存查找该请求结果,并根据该结果的缓存规则来决定是否适用缓存结果的过程。情况分为以下三种:

  • 不存在该缓存结果和缓存标识,无缓存,则直接向服务器发起请求(与第一次发起请求一致)
  • 存在该缓存结果和缓存标识,但该结果已失效,强制缓存失效,则使用协商缓存
  • 存在该缓存结果和缓存标识,且该结果尚未失效,强制缓存生效,直接返回结果
example

实现强缓存可以通过两种响应头实现:ExpiresCache-Control强缓存表示在缓存期间不需要请求,state code 为 200。举个栗子。

1
Expires: Wed, 22 Oct 2018 08:41:00 GMT

Expires 是 HTTP / 1.0 的产物,表示资源会在 Wed, 22 Oct 2018 08:41:00 GMT 后过期,需要再次请求。并且 Expires 受限于本地时间,如果修改了本地时间,可能会造成缓存失效。

1
Cache-control: max-age=30

Cache-Control 出现于 HTTP / 1.1,优先级高于 Expires 。该属性表示资源会在 30 秒后过期,需要再次请求。

协商缓存

协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,主要有以下两种情况:

  • 协商缓存生效,返回304
  • 协商缓存失效,返回200和请求结果

协商缓存需要客户端和服务端共同实现,和强缓存一样,也有两种实现方式。

Last-Modified 和 If-Modified-Since
  • Last-Modified 是服务器响应请求时,返回该资源文件在服务器最后被修改的时间
  • If-Modified-Since 则是在客户端再次发起请求时,将 Last-Modified 的值发送给服务器,询问服务器在该日期后资源是否有更新:
    • 有更新(If-Modified-Since值小于该资源在服务器的最后修改时间)的话就会将新的资源发送回来(状态码为200)
    • 若服务器在其失效前未更新则返回状态码304,表示可以继续使用缓存文件
  • 但是如果在本地打开缓存文件,就会造成 Last-Modified 被修改,所以在 HTTP / 1.1 出现了 ETag
ETag 和 If-None-Match

Etag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成)

ETag 类似于文件指纹,If-None-MatchRequest Header中的字段)会将当前ETagResponse Header中获取)发送给服务器,询问该资源ETag是否变动,有变动的话就将新的资源发送回来,状态码为200,否则返回304,继续使用缓存资源。

ETag是 HTTP/1.1 新出的请求头字段,自然优先级比Last-Modified高。

一张图总结一下

选择合适的缓存策略

对于大部分的场景都可以使用强缓存配合协商缓存解决,但是在一些特殊的地方可能需要选择特殊的缓存策略

  • 对于某些不需要缓存的资源,可以使用 Cache-control: no-store ,表示该资源不需要缓存
  • 对于频繁变动的资源,可以使用 Cache-Control: no-cache 并配合 ETag 使用,表示该资源已被缓存,但是每次都会发送请求询问资源是否更新。
  • 对于代码文件来说,通常使用 Cache-Control: max-age=31536000 并配合策略缓存使用,然后对文件进行指纹处理,一旦文件名变动就会立刻下载新的文件。