浅析浏览器缓存

前言
浏览器缓存对开发者来说一直都是一个有爱又恨的存在,一方面帮助开发者提升用户体验,另一方面有时会抽风,读取缓存展示错误的内容,因此,希望对浏览器缓存做一个总结,避免开发时因为缓存机制而过多耗费时间 。接下来,就进入浏览器缓存的世界
什么是缓存
缓存是指一个资源存在于服务器和客户端之间的副本,缓存会根据请求保存输出内容的副本,当下一个请求进来的时候,如果是相同的URL,缓存会根据缓存机制决定是直接使用副本响应还是向源服务器重新请求,当你访问一个网站时,打开调试面板,你会发现几乎静态资源请求都是从缓存中读取出来的,如图:

浅析浏览器缓存

文章插图
【浅析浏览器缓存】 
为什么要缓存
不用缓存可以吗?当然可以,至于后果是什么?试了就知道 。用了缓存之后,会有什么好处:
  • 减少网络带宽消耗 。无论对于网站运营方还是用户,带宽都是和钱挂钩的,当使用缓存时,产生的网络流量是极小的,对于两边都可以降低开销
  • 降低服务器压力 。当使用缓存时,可以有效减少用户对源服务器的请求,从而降低服务器压力
  • 加快网页打开速度,提升用户体验 。请求缓存比请求源服务器所话费的时间要短的多,因此内容可以更快的触达用户,以提升体验
浏览器缓存
前菜结束上硬菜,本篇主角浏览器缓存,浏览器缓存是众多web缓存分类中的一种,主要分为:
  • Memory Cache
  • Service Worker Cache
  • HTTP Cache
  • Push Cache
Memory Cache
Memory Cache指的是内存中的缓存,它有如下几个特点:
  • 响应速度最快,是浏览器请求时最先去尝试命中的缓存
  • 生命周期短,一旦进程被关闭就会被清空
  • 内存有限,资源存放位置随机
  • 不关心资源的HTTP缓存头的Cache-Control值,在同一个进程会被重用
来看一个例子:
浅析浏览器缓存

文章插图
 

浅析浏览器缓存

文章插图
 
第一张图是第一次打开网页时截取的,圈圈标记的图片时存放在Disk Cache里面的,第二张图时网页刷新时截取的,圈圈标记的图片是存放在Memory Cache中的,同样的图片两次为什么是从不同的缓存中读取的呢?因为Memory Cache进程关闭时就会清空,但是第二次刷新的时候,第一次浏览器解析图片文件进入Memory Cache,第二次刷新时由于Memory Cache是浏览器请求时最先去尝试命中的缓存,因此会直接去从Memory Cache中取Service Worker Cache
Service Worker是一种独立于主线程之外的JAVAScript线程,不会对当前程序的执行线程造成堵塞,通过Service Worker我们可以自由控制缓存哪些文件、如何匹配缓存、如何读取缓存,通过Service Worker实现的缓存称为Service Worker Cache,如果你对Service Worker有更深入了解的兴趣,可以去看看我之前的一篇博客:传送门
HTTP Cache
HTTP Cache是我们日常开发中接触最多也是最为熟悉的缓存,HTTP Cache通常可以分为强缓存和协商缓存,缓存策略都是通过HTTP Header来实现的,强缓存的优先级高于协商缓存,在命中强缓存失败的情况下才会去命中协商缓存
强缓存
强缓存主要通过设置HTTP Header Expires和Cache-Control两个字段控制,当请求发出时 。浏览器会根据上一次请求时记录的Expires和Cache-Control来判断是否命中强缓存,若命中则直接从强缓存中取资源,不会再向服务发送请求,当命中强缓存时,HTTP状态码返回200,且Size显示from disk cache,如图所示:
浅析浏览器缓存

文章插图
 
Expires
Expires缓存过期时间,值为一个时间戳 。如图:
浅析浏览器缓存

文章插图
 
当我们两次向同一个服务器请求资源时,第二次请求时,浏览器会先对比Expires时间戳和本地时间,如果本地时间小于Expires时间戳就会去缓存中取资源,但是这样存在一个问题,Expires依赖客户端时间,如果客户端时间和服务端时间不一致时,就会产生问题,Expires是HTTP1.0标准下的字段,考虑到这个问题,因此在HTTP1.1标准下新增了Cache-Control字段Cache-Control
Cache-Control字段是Expires字段的完全替代方案,它做Expires字段能做的所有事,还有Expires字段不能做的事情,当前还在用Expires字段的目的只是向下兼容,Cache-Control字段包含多个指令,这里介绍几个最常用的:


推荐阅读