前端缓存
前言
之前整理过浏览器缓存,总感觉少点什么,今天看到了一篇帖子,上面写道 大部分讨论缓存的文章会直接从HTTP协议头中的缓存字段开始,偶尔也会听别人讨论memory cache,disk cache等。那这两者分类体系究竟有何关联?是否有交叉?其实这也正是我想了解的,恰好本文主要是概念性的讲解,恰好get到了我的痛点,所以正好整理一下。
优先级
- Service Worker
- Memory Cache
- Disk Cache
- 网络请求
memory cache
memory cache是内存中的缓存,(与之相对的disk cache就是硬盘上的缓存)。按照操作系统的常理:先读取内存,再读取硬盘。
几乎所有的网络请求资源都会被浏览器自动加入到memory cache 中,但是也正因为数量很大但是浏览器占用的内存也不能无限扩大这两个因素,memory cache注定只能是个“短期存储”。常规情况下,浏览器的tab关闭后该次浏览的memory cache便会失效,而如果极端情况下,那可能在tab没关闭之前排在前面的缓存就已经失效。
memory cache机制保证了一个页面中如果有两个相同的请求(两个src相同的img,两个href相同的link)都实际只会被请求最多一次,避免浪费。
不过在匹配缓存时,除了匹配完全相同的URL之外,还会比对它们的类型,cors中的域名规则等。因此一个作为脚本(script)类型被缓存的资源是不能在图片类型中请求的,即便它们的src相等。
再从memory cache获取缓存内容时,浏览器会忽略例如max-age=0,no-cache等头部配置。例如页面上存在几个相同的src图片,即便它们可能被设置为不缓存,但依然会从memory cache中读取。这是因为memory cache只是短期使用,大部分情况生命周期只有一次浏览而已。而max-age=0在语义上普遍被解读为“不要在下次浏览时使用”,所以和memory cache并不冲突。
但如果真心不想一个资源进入缓存,连短期也不行,那就需要使用no-store。存在这个头部配置的话,即便是memory cache也不会存储,自然不会从中读取。
disk cache
disk cache 也叫 HTTP cache,顾名思义是存储在硬盘上的缓存,因此它是持久存储的,是实际存在于文件系统中的。而且它允许相同的资源在跨会话,甚至跨站点的情况下使用,例如两个站点都使用了同一张图片。
disk cache 会严格根据 HTTP 头信息中的各类字段来判定哪些资源可以缓存,哪些资源不可以缓存;哪些资源是仍然可用的,哪些资源是过时需要重新请求的。当命中缓存之后,浏览器会从硬盘中读取资源,虽然比起从内存中读取慢了一些,但比起网络请求还是快了不少的。绝大部分的缓存都来自 disk cache。
凡是持久性存储都会面临容量增长的问题,disk cache 也不例外。在浏览器自动清理时,会有神秘的算法去把“最老的”或者“最可能过时的”资源删除,因此是一个一个删除的。不过每个浏览器识别“最老的”和“最可能过时的”资源的算法不尽相同,可能也是它们差异性的体现。
Service Worker
上述的缓存策略以及缓存/读取/失效的动作都是由浏览器内部判断 & 进行的,我们只能设置响应头的某些字段来告诉浏览器,而不能自己操作。但 Service Worker 的出现,给予了我们另外一种更加灵活,更加直接的操作方式。
Service Worker 能够操作的缓存是有别于浏览器内部的 memory cache 或者 disk cache 的。我们可以从 Chrome 的 F12 中,Application -> Cache Storage 找到这个。除了位置不同之外,这个缓存是永久性的,即关闭 TAB 或者浏览器,下次打开依然还在(而 memory cache 不是)。有两种情况会导致这个缓存中的资源被清除:手动调用 API cache.delete(resource)
或者容量超过限制,被浏览器全部清空。
如果 Service Worker 没能命中缓存,一般情况会使用 fetch()
方法继续获取资源。这时候,浏览器就去 memory cache 或者 disk cache 进行下一次找缓存的工作了。注意:经过 Service Worker 的 fetch()
方法获取的资源,即便它并没有命中 Service Worker 缓存,甚至实际走了网络请求,也会标注为 from ServiceWorker
。