浏览器的缓存机制

160 阅读6分钟

前言

缓存可以说是性能优化中简单高效的一种优化方式了。一个优秀的缓存策略可以缩短网页请求资源的距离,减少延迟,并且由于缓存文件可以重复利用,还可以减少带宽,降低网络负荷。

对于一个数据请求来说,可以分为发起网络请求、后端处理、浏览器响应三个步骤。浏览器缓存可以帮助我们在第一和第三步骤中优化性能。比如说直接使用缓存而不发起请求,或者发起了请求但后端存储的数据和前端一致,那么就没有必要再将数据回传回来,这样就减少了响应数据。

接下来将从以下三点开始介绍: 1. 缓存位置 2. 缓存策略 3. 实际场景应用缓存策略

缓存位置

从缓存位置上来说分为四种,并且各自有优先级,当依次查找缓存且都没有命中的时候,才会去请求网络。

  1. Service Worker
  2. Memory Cache
  3. Disk Cache
  4. Push Cache
  5. 网络请求

1.Service Worker

运行在浏览器背后的独立线程,一般可以用来实现缓存功能。使用Service Worker的 话,传输协议必须是HTTPS,因为Service Worker中涉及到了请求拦截 Service Worker实现缓存的三个步骤:首先需要注册Service Worker,然后监听到 install事件以后就可以缓存需要的文件,在下一次用户访问的时候就可以通过拦截请求的 方式查询是否存在缓存,存在缓存的话就可以直接读取缓存文件,否则就去请求数据。

2.Memory Cache

内存中的缓存,读取内存中的数据比读取磁盘数据快,但是内存缓存读取高效,可是缓存持续性很短,随着进程的释放 (关闭tab页面) 就会释放。

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

3.Disk Cache

硬盘缓存,虽然读取的速度慢了点,但是Disk Cache胜在容量大和存储的时效性高,他会根据HTTP Header中的字段判断那些资源需要缓存,哪些资源可以不请求直接用,哪些资源已经过期需要重新请求。

4.Push Cache

当以上三种缓存都没有命中的时候,它才会被使用,并且缓存时间很短,只在会话中存在,一旦会话结束就会被释放。

缓存策略

  1. 强缓存
  2. 协商缓存 都是通过HTTP Heade来实现的

1.强缓存

可以设置 HTTP Header为:Expires 或者 Cache-Control只要是开启了强缓存的文件,在缓存期间是不需要请求的

Expires:Wed, 22 Oct 08:12:00 GMT.表示资源会在Wed, 22 Oct 08:12:00 GMT后过期,需要再次请求(受限于本地时间,如果修改本地时间,可能会造成缓存失效)

Cache-Control:max-age=30表示资源会在 30秒后过期,需要再次请求

2.协商缓存

当强缓存到期了,就要发起请求验证资源是否有更新,如果没有更新,服务端返回304,那么直接更新强缓存的有效期。

可以设置 HTTP Header为:Last-Modified 或者 ETag。
Last-Modified:表示本地文件最后一次修改的日期,当协商缓存执行时,会询问服务器在该日期后资源是否有更新 (缺点:只要本地打开了缓存文件,即使没有修改文件,也会造成Last-Modified被修改)。
ETag:对比文件内容来确定文件是否被修改,类似于文件的指纹,将ETag发送给服务端,询问该资源的ETag有没有变动,没有的话就直接更新强缓存的有效期。

3.缓存过程

1.浏览器第一次加载资源,服务器返回200,浏览器将资源文件从服务器上请求下载下来,并把response header及该请求的返回时间一并缓存;

2.下一次加载资源时,先比较当前时间和上一次返回200时的时间差,如果没有超过cache-control设置的max-age,则没有过期,命中强缓存,不发请求直接从本地缓存读取该文件(如果浏览器不支持HTTP1.1,则用expires判断是否过期);如果时间过期,则向服务器发送header带有If-None-Match和If-Modified-Since的请求

3.服务器收到请求后,优先根据Etag的值判断被请求的文件有没有做修改,Etag值一致则没有修改,命中协商缓存,返回304;如果不一致则有改动,直接返回新的资源文件带上新的Etag值并返回200;

4.如果服务器收到的请求没有Etag值,则将If-Modified-Since和被请求文件的最后修改时间做比对,一致则命中协商缓存,返回304;不一致则返回新的last-modified和文件并返回200;

过程如图所示

578c0c11eb642f0454eb24d602673bc9 (1).jpg

实际场景应用缓存策略

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 等) 均采用这个模式。

最后

有这样一个问题

如果什么缓存策略都没有的设置的话,浏览器会怎么处理?

浏览器会启用一个启发式算法,通常会取响应头中的Date减去Last-Modified的值的10% 作为缓存时间。

参考文章:
彻底吃透浏览器的缓存机制
浏览器的缓存机制小结