缓存策略作为前端性能优化的重要环节,直接影响用户体验。若使用了缓存策略,用户二次访问时加快页面打开速度,提高用户体验,另外还能降低服务器压力。
一、浏览器缓存机制
1.1 强缓存
不使用缓存:
使用缓存:
我们可以看到消耗的时间from memory cache的时候为0,from disk cache的时候也减少了60%以上。
1.1.1 memory cache和disk cache的区别
缓存类型 | 读取位置 | 读取速度 | 生命周期 |
---|---|---|---|
memory cache | 内存 | 读取速度快,优先级高 | 生命周期短,页面关闭就释放内存,只能存小文件 |
disk cache | 硬盘 | 读取速度相对较慢 | 生命周期长,不手动删除会一直存在,可存储大文件 |
1.1.2 强缓存字段
浏览器首次请求资源时,当服务器收到请求,可根据请求资源类型,在HTTP响应头(Response Headers) 中添加强缓存控制字段Expires和Cache-Control,浏览器根据标识将资源进行缓存。
优先级 | 响应头 | |
---|---|---|
Expires | 低(HTTP/1.0) | Expires: Fir, 11 Aug 2023 02:29:06 GMT 过期时间,可能因为时区不同或客户端和服务端时间有误差等原因,导致强缓存失效 |
Cache-Control | 高(HTTP/1.1) | Cache-Control: max-age=2592000 一个相对值,根据当前时间计算出过期时间 |
Cache-Control取值:
- public: 代理服务器或中间服务器,客户端都可以缓存该内容
- private(默认值):只有客户端能缓存
- no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
- no-store:不使用缓存,既不使用强缓存也不使用协商缓存
- max-age=xxx:缓存内容在xxx秒后失效
1.2 协商缓存
我们有时候还能看到有状态码为304的请求,这就是协商缓存生效的结果。
1.2.1 协商缓存字段
- Last-Modified/If-Modified-Since: Last-Modified:服务器响应头,该资源在服务器最后被修改的时间。 If-Modified-Since:客户端再次发起该请求时,携带的上次请求回来的Last-Modified值,服务器收到之后与该资源最后一次修改的时间做对比,若大于该值,则表示该资源被修改了,重新返回资源,状态码为200,否则表示未被修改,状态码为304,告诉客户端继续使用缓存内容。
- Etag/If-None-Match: Etag:当前资源的唯一标识,由服务端生成。 If-None-Match:客户端再次发起请求时,携带上次请求回来的Etag,服务器端收到后,将其与资源的Etag做对比,若不同,则返回最新资源,状态码为200,否则表示未被修改,状态码为304,告诉客户端继续使用缓存内容。
注:Etag优先级高于Last-Modified,因为修改时间,可能会因为时区或客户端与服务器时间不一致,导致失效。
1.3 请求资源的过程
二、前端静态资源缓存策略
前端哪些资源是需要强缓存,哪些需要协商缓存?
2.1 前端静态资源
前端静态资源一般包括:js,css,图片
我们在使用打包工具打包时,通常会对js/css文件输出带hash的路径,或对经常变化的文件生成为chunk。
以webpack为例:
打包后的结果为:
2.2 缓存策略
我们整体的策略是对带hash路径和图片类的资源进行强缓存,其他的进行协商缓存。
以 Nginx 为例,做以下配置:
location / {
if ($request_filename ~* ^.*[.](html|htm)$) {
# html文件不缓存
expires 0;
add_header Cache-Control "no-store";
}
if ($request_filename ~* .*.(js|css|json)$) {
# 不带hash的js,css,json协商缓存
add_header Cache-Control "no-cache";
}
if ($request_filename ~* .*.(chunk).(css|js)$) {
# 带hash的js,css强缓存一个月
add_header Cache-Control "max-age=2592000";
}
if ($request_uri ~* .*[.](png|jpg|svg|ico)$) {
# 图片强缓存一个月
add_header Cache-Control "max-age=2592000";
}
}