浏览器缓存机制

3,083 阅读7分钟

缓存可以说是性能优化中简单高效的一种优化方式了,他可以显著减少网络传输带来的消耗。
对于一个数据请求来说,可以分为发起网络请求、后端处理、浏览器响应三个步骤。浏览器缓存可以帮助我们在第一和第三步骤中优化性能。

什么是缓存

当我们第一次访问网站的时候,比如juejin.cn,浏览器会把网站上的图片和数据下载到本地,当我们再次访问的时候,网站资源就会从本地加载出来,这就是缓存。

缓存的好处

  1. 缓解服务器压力,不用每次都去请求某些资源
  2. 提升性能,打开本地资源肯定会比请求服务来的快
  3. 减少带宽消耗,当我们使用缓存时,只会产生很小的网络消耗。 web缓存种类:数据库缓存、CDN缓存,代理服务器缓存,浏览器缓存

缓存位置

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

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

Service Worker

Service Worker的缓存与浏览器其他内建的缓存机制不同,它可以让我们自由控制缓存文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。
当Service Worker没有命中缓存的时候,就会调用fetch函数获取数据。也就是说,没有在Service Worker 命中缓存的话,会根据缓存查找优先级取查找数据。但是是从Memory Cache中还是从网络请求中获取的数据,浏览器就显示我们是从Service Worker中获取的内容。

Memory Cache

Memory Cache也就是内存中的缓存,读取内存中的数据当然比磁盘快。但是内存缓存虽然读取快,但缓存的持续性很短,会随着进程的释放而释放。一旦我们关闭Tab页面,内存中的缓存也就被释放了。

当我们访问过页面后,再次刷新页面,可以发现很多数据都来自内存缓存。

image.png

既然内存缓存这么快,为什么不能数据都存在放在内存中呢?这是因为 首先计算机的内存一般比硬盘容量小的多,操作系统需要精打细算内存的使用,所以能使用的内存必然不多。

Disk Cache

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

Push Cache

Push Cache 是HTTP/2中的内容,当以上三种缓存都没有命中时,它才会被使用,并且缓存时间也很短暂,只会在会话(Session)中存在,一旦会话结束就被释放。

网络请求

如果所有缓存都没有命中的话,就只能发起请求来获取资源了。

缓存策略

通常浏览器缓存策略分为两种:强缓存和协商缓存。并且缓存策略都是通过设置HTTP Header来实现的。

强缓存

强缓存可以通过两种HTTP Header实现:ExpiresCache-Control强缓存表示缓存期间不需要请求,state-code为200

Expires

expires:Sat, 17 Dec 2022 03:30:46 GMT

Expires是HTTP/1的产物,表示资源会在Sat, 17 Dec 2022 03:30:46 GMT后过期,需要再次请求。并且Expires受限于本地时间,如果修改了本地时间,可能会造成缓存失效。

Cache-control

cache-control:max-age=31536000

cache-control出现在HTTP/1.1,优先级高于Expires。该属性值表示资源会在31536000s后过期,需要再次请求。

常见指令的作用

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

协商缓存

向服务器发送请求,服务器会根据这个请求的request header的一些参数来判断是否命中协商缓存,如果命中,则返回304状态码并带上新的response header通知浏览器从缓存中读取资源
协商缓存可以通过设置HTTP Header实现:Last-ModifiedEtag
当浏览器发起请求验证资源时,如果资源没有做任何改变,那么服务器就会返回304状态码,并且更新浏览器缓存有效期。

Last-Modified 和 if-Modified-Since
Last-Modified表示本地文件最后修改日期,If-Modified-Since会将Last-Modified的值发送给服务器,询问服务器该日期后资源是否有更新,若有更新就会将新的资源发送回来,否则返回304状态码。

Last-Modified存在的弊端:

  • 如果服务端打开缓存文件,即使没有对文件进行修改,还是会造成Last Modified被修改,服务端不能命中缓存然后发送相同资源。
  • 因为Last-Modified只能以秒计算,如果在不可感知的时间内修改完成文件,那么服务器会认为资源还是命中了,不会返回正确的资源。
    因为上面这两个弊端,所以在HTTP/1.1出现Etag

Etag 和 if-None-Match
Etag类似文件指纹,If-None-Match会将当前Etag发送给服务器,询问改资源Etag是否变动,有变动就将新资源发送回来。EtagLast-Modified优先级高。

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

实际场景应用缓存策略

频繁变动的资源

对于频繁变动的资源,首先需要使用Cache-Control: no-cache使浏览器每次都请求服务器,然后配合EtagLast-Modified来验证资源是否有效,这样做法虽然不能节省请求数量,但是显著减少响应数据大小。

代码文件

这里指HTML外的代码文件,因为html文件一般不缓存或缓存时间很短。
一般来说,现在会使用打包工具来打包代码,那么我们就可以对文件名进行哈希处理,只有当代码修改后才会生成新的文件名。基于此,我们就可以给代码文件设置缓存有效期Cache-Conttrol: max-age=3153600,这样只有html文件引入的文件名发生变更才会去下载最新的代码文件,否则就一直使用缓存。

刷新操作方式,对缓存的影响

描述操作强缓存协商缓存
正常操作地址栏输入url,跳转链接,前进后退有效有效
手动刷新f5,点击刷新按钮,右击菜单刷新失效有效
强制刷新ctrl + f5失效失效

参考资料

前端浏览器缓存知识梳理 你知道304吗?图解强缓存和协商缓存