前言
缓存是性能优化中非常重要的一环,浏览器的缓存机制对开发也是非常重要的知识点。接下来以三个部分来把浏览器的缓存机制说清楚:
❝强缓存 协商缓存 缓存位置
❞
缓存分析
- 先根据这个资源的一些 http header 判断它是否命中强缓存,如果命中,则直接从本地获取缓存资源,不会发请求到服务器;
- 当强缓存没有命中时,客户端会发送请求到服务器,服务器通过另一些request header验证这个资源是否命中协商缓存,称为http再验证,如果命中,服务器将请求返回,但不返回资源,而是告诉客户端直接从缓存中获取,客户端收到返回后就会从缓存中获取资源;
- 浏览器每次发起请求,都会先在浏览器缓存中查找该请求的结果以及缓存标识
- 浏览器每次拿到返回的请求结果都会将该结果和缓存标识存入浏览器缓存中
- 强缓存和协商缓存共同之处在于,如果命中缓存,服务器都不会返回资源; -区别是,强缓存不对发送请求到服务器,但协商缓存会。
- 当协商缓存也没命中时,服务器就会将资源发送回客户端。
❝第一次请求(必进行)-->请求结果和缓存标识存入浏览器缓存---> 第二次请求---->强缓存--->协商缓存--->请求 强制缓存优先于协商缓存进行,若强制缓存生效则直接使用缓存,若不生效则进行协商缓存--->协商不生效直接进行请求
❞
缓存位置
浏览器中的缓存位置一共有四种,按优先级从高到低排列分别是:
- Service Worker
- Memory Cache
- Disk Cache
- Push Cache
Service Worker (浏览器缓存)
是运行在浏览器背后的独立线程,一般可以用来实现缓存功能。
Service Worker 借鉴了 Web Worker的 思路,即让 JS 运行在主线程之外,由于它脱离了浏览器的窗体,因此无法直接访问DOM。虽然如此,但它仍然能帮助我们完成很多有用的功能,比如离线缓存、消息推送和网络代理等功能。其中的离线缓存就是 Service Worker Cache。
Memory Cache(内存缓存) 和 Disk Cache(磁盘缓存)
Memory Cache 指的是内存缓存,从效率上讲它是最快的。但是从存活时间来讲又是最短的,当渲染进程结束后,内存缓存也就不存在了。
Disk Cache 指的是存储在磁盘中的缓存,从存取效率上讲是比内存缓存慢的,但是他的优势在于存储容量和存储时长。
Push Cache(推送缓存,最后选项)
这是浏览器缓存的最后一道防线。它是 HTTP/2 中的内容,虽然现在应用的并不广泛,但随着 HTTP/2 的推广,它的应用越来越广泛。
当以上三种缓存都没有命中时,它才会被使用
-大家可以参考这篇 点我跳转
强缓存
「浏览器中的缓存作用分为两种情况,一种是需要发送HTTP请求,一种是不需要发送。」
首先是检查强缓存,这个阶段不需要发送HTTP请求。
根据HTTP版本的不同检查 expire 和 cache-control
在早期,也就是HTTP/1.0时期,使用的是Expires,而HTTP/1.1使用的是Cache-Control。让我们首先来看看Expires。
Expires
「代表该资源的过期时间。」
Expires: Wed, 22 Oct 2018 08:41:00 GMT
//表示资源会在 Wed, 22 Oct 2018 08:41:00 GMT 后过期,需要再次请求。
看起来没什么问题,但是存在一个隐患 ↓
「Expires 是 HTTP/1 的产物,受限于本地时间,如果修改了本地时间,可能会造成缓存失效」
Cache-Control
「采用过期时长来控制缓存」
Cache-Control:max-age=100, must-revalidate, public
- 该字段表示,缓存的有效时间为100秒,之后访问需要向源服务器发送请求验证,此缓存可被代理服务器和客户端缓存。
两者区别
区别就在于 Expires 是http1.0的产物,Cache-Control是http1.1的产物,
两者同时存在的话,Cache-Control优先级高于Expires;
在不支持HTTP/1.1的环境下, Expires就会发挥作用, 所以现阶段的存在是为了做一些兼容的处理.
协商缓存
「协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程」
- 协商缓存分两种 Etag和Last-Modified
Last-Modified
「即最后修改时间。在浏览器第一次给服务器发送请求后,服务器会在响应头中加上这个字段。」
浏览器在第一次访问资源时
- 服务器返回资源的同时,在response header中添加 Last-Modified,Last-Modified值为该资源在服务器上最后的修改时间,浏览器接收后缓存文件和header;
浏览器第二次请求这个资源
- 浏览器检测到有 Last-Modified这个header,于是将Last-Modified中的值 添加到 If-Modified-Since;
后续请求
- 服务器拿到请求头中的If-Modified-Since的字段后,其实会和这个服务器中该资源的最后修改时间对比:
- 如果请求头中的这个值小于最后修改时间,说明是时候更新了。返回新的资源,跟常规的HTTP请求响应的流程一样。
- 否则返回304,告诉浏览器直接用缓存。
- 服务器拿到请求头中的If-Modified-Since的字段后,其实会和这个服务器中该资源的最后修改时间对比:
ETag
「资源标识符」
给文件生成的唯一标识,只要里面的内容有改动,这个值就会变。服务器通过响应头把这个值给浏览器。
浏览器在下一次加载资源向服务器发送请求时,会将上一次返回的Etag值放到request header里的If-None-Match里,服务器只需要比较客户端传来的If-None-Match跟自己服务器上该资源的ETag是否一致,就能很好地判断资源相对客户端而言是否被修改过了。
❝这种模式想起了cookie和session
❞
两者区别
「在精准度上」,ETag优于Last-Modified。优于 ETag 是按照内容给资源上标识,因此能准确感知资源的变化。而 Last-Modified 就不一样了,它在一些特殊的情况并不能准确感知资源变化,主要有两种情况:
编辑了资源文件,但是文件内容并没有更改,这样也会造成缓存失效。 Last-Modified 能够感知的单位时间是秒,如果文件在 1 秒内改变了多次,那么这时候的 Last-Modified 并没有体现出修改了。
「在性能上」,Last-Modified优于ETag,也很简单理解,Last-Modified仅仅只是记录一个时间点,而 Etag需要根据文件的具体内容生成哈希值。
另外,如果两种方式都支持的话,服务器会优先考虑ETag。
❝好了浏览器缓存就介绍到这里,我是将笔记挑了些重点出来,如果有哪里有问题请指出来我会洗耳倾听 >v<