浏览器的缓存主要集中在HTTP的 "请求"(Request) 和 "响应"(Response) 中。
- 在 Request 过程中,浏览器可以通过 Cache 的结果选择直接使用缓存,减少了HTTP请求的次数
- 在 Response 过程中,服务器与浏览器之间存在校验和判断机制,也可以因缓存的存在而减少传输的资源,加快响应速度。
按照缓存的存储位置可分为以下几类:
- Service Worker
- memory cache
- disk cache
- network request
上述四类缓存的顺序是按照优先级排列的,如果一项得到响应就不会再继续往下判断,这也是符合逻辑的。
Service Worker
因为 Service Worker 是要在启用了服务的页面才会出现,所以需要在注册 serviceWorker 页面中找到,例如 使用了 Google 的 PWA(渐进式Web应用) 页面中都可以发现。Service Worker 实例、有韦二姐参与的微博PWA
Service Worker 是一个注册在指定源和路径下事件驱动的独立线程,采用 JavaScrip t控制关联的页面或者网站资源,拦截并修改访问和资源请求,更精细地缓存资源。
Service Worker 可以拦截请求,所以需要使用 HTTPS 协议,Service Worker 的缓存是永久性的,关闭浏览器打开还是存在,除了手动调用API清除以及存储容量超过限制被清除外,一般都能持续存在。
Service Worker 使用之前需要先注册,在注册成功后浏览器会尝试为页面安装并激活ServiceWorker,在安装过程需要缓存一些静态资源(使用 cache 全局对象存储响应收到的资源)。
后续的HTTP请求都会被 Service Worker 拦截,如果请求的资源是 Service Worker控制的,都会触发 fetch 事件,在处理 fetch 事件过程中,可以使用 caches.match(event.request) 来对网络请求的资源和 cache 里可获取的资源进行匹配,查看是否缓存中有相应的资源,如果匹配到缓存中的资源直接使用。如果没有在缓存中找到匹配的资源,可以控制浏览器对着资源直接去 fetch 默认的网络请求。具体过程如下图所示:
整个过程中,即使最后请求了网络资源,只要通过了 Service Worker的 fetch 事件,网络请求均会包括 from ServiceWorker。
memory cache
memory cache 是内存中的缓存,在尝试读取本地缓存时,总是先读内存,再读硬盘,毕竟访问内存更快。
几乎所有的请求资源都可以放入 memory cache ,与 memory cache 相关的机制有 preloader 和 preload 两种:
- preloader 浏览器在解析和执行 JavaScript 和 CSS 资源时,可以使用 preloader 机制请求下一批资源,然后放入 memory cache 中,供以后解析和执行这些资源时使用。
- preload 可以显式指定需要预加载的资源,也是放入 memory cache 中供后续使用
一个页面中如果有很多个相同的请求,memory cache 的机制可以保证实际只会最多被请求一次,可以减少HTTP请求的资源浪费。
memory cache 在匹配缓存资源时,处理对比资源的 URL 外,还会对比Content-Type,CORS域名规则等其他特征,只有完全一样的资源请求才会被匹配。
memory cache 缓存的资源,在标签页关闭后就会失效,只是一个 短期存储。如果内存中缓存的资源过多,也会提前失效。
memory cache 获取资源时,浏览器会忽视 HTTP 的头部配置,例如 max-age=0, no-cache 等,即使设置的意思表示不缓存,下次请求还是先从 memory cache 中读取资源。只有头部使用 no-store 时,memory-cache 不会存储资源,需要直接从服务器获取。