缓存是一个老生常谈的话题 经常被作为前端面试的一个知识点
再介绍缓存的时候我们经常将缓存分为强缓存 和 协商缓存 两种,两者的主要区别在于本地缓存的时候, 时候发需要向服务器确认本地缓存依然有效, 协商缓存顾名思义就是需要和服务器确认本地缓存是否有效。
两种缓存方案的问题点
强缓存
我们知道强缓存主要通过http请求头中的Cache-Control 和 Expire 两个字段控制, Expire是http1.0的标准, 在这里我们可以忽略, 我们主要来讨论CacheControl两个字段, 一般我们会设置Cache-Control的值为”public,max-age=xxx”,表示xxx秒内再次访问该资源,均使用本地缓存,不再向服务器发请求
显而易见 如果在xxx秒内,服务器上的资源更新了 客户端再没有强制刷新的情况下。看到的内容依然是旧的,这个时候加入这个资源是js脚本,脚本里有接口请求,正好发版,后端的接口变了就gg了,旧的脚本就拿不到数据了 可能还会报错。
协商缓存
协商缓存的最大问题就是每次都要向服务器眼哼以下有效性。看起来很省事,不管那么多都问一下是否有效,但是对于一个有追求的码农,这是不能接受的,每次都去请求那还要缓存有什么意义
最佳实践
缓存的意义就是在于减少请求,更多的使用本地资源 给用户根号的体验,也减轻服务器的压力,所以最佳实践尽可能命中强缓存。同时能在更新版本的时候让客户端的缓存时效。
综上所述,我们就得到了一个较为合理的方案
- html使用协商缓存
- css/js/图片 使用强缓存 文件名带上hash值
哈希也有讲究
前端小伙都知道,文件hash是可以通过webpack打包提供的,webpack给我们提供了三种方式,分别是hash,chunkhash 和 contenthash 那么三者有什么区别呢?
- hash 跟整个项目的构建有关,构建生成的文件hash值都是一样的,只要项目里的文件有修改,整个项目的hash都会更改
- chunkhash 根据不同的入口文件的依赖进行依赖解析,构建对应的chunk,生成对应的hash
- contenthash 由文件内容产生的hash值 内容各不同产生的contenthash也不一样
显然我们不会使用第一种 改了一个文件以后所有的hash都变了,缓存就失效了。这不是我们想要的
那么 chunkhash 和 contenthash 的主要应用场景是什么呢?
在实际项目中 我们一般会把项目中的css抽离出来加以引用,如果我们使用chunkhash 当我们的css 代码改变之后 就会发现css文件的hash值改变的同事,js文件的hash值也会该拜年,这时候contenthash 就排上用场了
ETag 与 Last-Modified 谁优先
一般来说 是Etag 优先
后端怎么设置
上文说到的是前端如何打包, 那么后端应该怎么做呢? 我们知道浏览器根据相应的响应头字段来巨鼎缓存方案,
所以如果要设置强缓存res.setHeader(Cache-Control,public,max-age=xxx)
如果要协商缓存 res.setHeader(Cache-Control,public,max-age=0)
res.setHeader(Last-modified,xxx)
res.setHeader(Etag,xxxx)
总结
在做前端缓存的时候,我们尽可能的设置长时间的强缓存,通过文件名加hash的方式来做版本更新。在代码分包的时候应该将一些不常用的公共库打包出来使其能够长久缓存