这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战
在性能优化过程中,浏览器缓存是必不可少的优化环节,且浏览器缓存对于性能优化可以起到立竿见影的作用
在面试过程中,浏览器缓存的知识也是一道高频的问题,掌握浏览器缓存有利于更好的面试
浏览器缓存
缓存在不同的工种种都有不同的具体场景,在数据库缓存、Redis缓存、CDN缓存和浏览器缓存等,身为前端需要重点浏览器缓存
浏览器缓存是什么:
HTTP 缓存(或 Web 缓存)是用于临时存储(缓存)Web文档(如 HTML 页面和图像),以减少服务器延迟的一种信息技术。HTTP 缓存系统会保存下通过这套系统的文档的副本;如果满足某些条件,则可以由缓存满足后续请求。HTTP 缓存系统既可以指设备,也可以指计算机程序。
缓存的作用:
避免不必要的数据传输、提升页面加载和展示速度、减轻服务端负担:当用户打开过网站之后,若是浏览器对相关资源没有过期,不需要再次通过请求获取资源而直接使用浏览器缓存资源,可以在这个过程中节省HTTP请求,提高资源的到达时间,加快资源的解析时间,进而使得页面打开速度变快。当请求数量减少,那么服务端可以节省很多HTTP的通信的资源
缓存分类:
按照缓缓失效策略分类,可以将缓存分为:强缓存(本地缓存)、协商缓存(弱缓存)两类
强缓存(本地缓存)
强缓存是指当浏览器第一次请求后,通过设置Http Header实现缓存,在缓存有效时间内,当浏览器需要再次加载资源时不需要请求服务器,直接使用浏览器本地的缓存资源
强缓存主要概念:Expires 和 Cache-Control
为何会出现两种设置强缓存的方式呢?
Expires:
在HTTP1.0时期,规定通过设置 HTTP Header的 Expires是现实缓存,对应的值一个时间戳,当浏览器第一次访问站点之后,服务端会在响应的Http Header中下发 Expires字段,那么当浏览器再次需要使用资源的时候,会先对比当前设备的时间和Expires中设置的时间,如果当前设备时间早于Expires,那么直接使用浏览器缓存的资源,若晚于则需要再次发送请求
设置Expires:
Expires: Sat, 07 Aug 2021 07:38:29 GMT
复制代码
设置的Expires时告诉浏览器,在2021-08-07 07:38:29时间之前,想要使用设置了该Expires资源时都是直接使用浏览器本地缓存资源
Expires: -999
复制代码
当设置为负数的时候,是告诉浏览器资源被缓存,但是立即失效,需要使用协商缓存
Expires缺陷:
- 可能会因为服务器和客户端的 GMT 时间不同,出现偏差
- 如果修改了本地时间,那么客户端端日期可能不准确
- 写法太复杂,字符串多个空格,少个字母,都会导致非法属性从而设置失效
Cache-Control:
在 HTTP 1.1时期,HTTP使用 Cache-control 这个响应头,这个头部对比Expires更加强大,具有更灵活的配置:
private:表示私有缓存,只可以被客户端缓存,不能被共有缓存代理服务器缓存,不能在用户间共享
public:表示共有缓存,可以被客户端和被代理服务器缓存,比如 CDN,允许多用户间共享
max-age:值以秒为单位,表示缓存的内容会在该值后过期,max-age: 100 表示缓存时间在100秒之后过期
s-maxage:值以秒为单位,覆盖max-age,作用一样但是仅在代理服务器中生效
no-cache:资源被缓存,但是立即失效,需要使用协商缓存(需要通过请求验证资源是否过期)
no-store:所有内容都不会被缓存
must-revalidate:告诉浏览器,你这必须再次验证检查信息是否过期, 返回的代号就不是 200 而是 304 了
单独设置
cache-control: max-age=31536000
复制代码
表示该资源缓存时间在31536000秒之后过期
组合设置:可以同时设置多个
cache-control: public, max-age=31536000
复制代码
表示该资源可以被客户端和代理服务器缓存,但是该资源在31536000秒之后过期
强缓存优先级:
当同时存在Expires和Cache-Control: max-age=100时,HTTP规定max-age的优先级更高,会覆盖Expires
协商缓存(弱缓存)
现在有一个JS资源,为其设置了强缓存时间,但是在该强缓存时间内并没有更新JS资源,浏览器会重新加载资源,即便这个资源并没有修改。若是在强缓存时间内更新了JS资源,但是浏览器并不会重新加载最新的资源,继续使用老版本的JS资源。如何设置强缓存时间便是一个令人头疼的事情
强缓存虽然很好,但是也存在其短板,这个时候就该协商缓存出场了
协商缓存过程:在浏览器端,当对某个资源的请求没有命中强缓存时,浏览器就会发一个请求到服务器,验证协商缓存是否命中,如果协商缓存命中,请求响应返回的 HTTP 状态为 304。
协商缓存主要是设置两对好基友来实现:Last-Modified 和 If-Modified-Since、ETag、If-None-Match
Last-Modified,If-Modified-Since的协商缓存过程:
- 浏览器第一次请求资源,服务端在返回资源的响应头中加入 Last-Modified 字段,这个字段表示这个资源在服务器上的最近修改时间
Last-Modified: Sat, 07 Aug 2021 07:38:29 GMT
复制代码
- 浏览器收到响应,并记录 Last-Modified 这个响应头的值为 T
- 当浏览器再次向服务端请求该资源时,请求头加上 If-Modified-Since 的 header,这个 If-Modified-Since 的值正是上一次请求该资源时,后端返回的 Last-Modified 响应头值 T
- 服务端再次收到请求,根据请求头 If-Modified-Since 的值 T,判断相关资源是否在 T 时间后有变化;如果没有变化则返回 304 Not Modified,且并不返回资源内容,浏览器使用资源缓存值;如果有变化,则正常返回资源内容,且更新 Last-Modified 响应头内容
ETag、If-None-Match 协商缓存过程和Last-Modified,If-Modified-Since一致,区别在于Etag和 Last-Modified 生成方式不一致
Last-Modified是根据资源的最后修改时间生成
Etag是根据资源的内容生成
协商缓存优先级:
Etag 优先级比 Last-Modified 高,如果他们组合出现在请求头当中,浏览器会优先采用 Etag 策略
总结
强缓存和协商缓存优先级:
优先级上:Cache-Control > Expires > ETag > Last-Modified
使用场景:
强制缓存优先级最高,并且资源的改动在缓存有效期内浏览器都不会发送请求,因此强制缓存的使用适用于大型且不易修改的的资源文件,例如第三方 CSS、JS 文件或图片资源
协商缓存灵活性高,适用于数据的缓存,根据上述知识的介绍,采用 Etag 标识进行对比灵活度最高,也最为可靠。对于数据的缓存,可以重点考虑存入内存中,因为内存加载速最快,并且数据体积小