前端缓存笔记

Published: · LastMod: October 05, 2022 · 1935 words

缓存分类 🔗

image.png

HTTP缓存 🔗

Expires 🔗

缓存的绝对过期时间,此时间之后缓存都会失效

Expires过期时间会受到客户端时间影响变得不精准

Cache-Control 🔗

控制缓存的行为

  • max-age: 缓存过期的相对时间, 和Expires相比,优先级更高

  • s-maxage: 只在公共缓存服务器生效,比如资源从源服务器发出后又被中间的代理服务器接收并缓存。直接忽略 Expires 和 max-age 指令的值。代理服务器中s-maxage优先级高于max-age

  • public: 该资源可以被任何节点缓存

  • private: 该资源只提供给客户端缓存,代理服务器不会进行缓存。(同时当设置了 private 指令后 s-maxage 指令将被忽略。

  • no-cache、no store:

    • no store 才是真正的不进行任何缓存。

    • 当 no-cache 在请求首部中被使用时,表示告知(代理)服务器不直接使用缓存,要求向源服务器发起请求,而当在响应首部中被返回时,表示客户端可以缓存资源,但每次使用缓存资源前都必须先向服务器确认其有效性,这对每次访问都需要确认身份的应用来说很有用。

      1
      
      <meta http-equiv="Cache-Control" content="no-cache" />
      
  • Last-Modified 与 If-Modified-Since:是否更新

    • 资源没有更新,304 Not Modified 的响应
  • Etag 与 If-None-Match

    • etag优先级高于Last-Modified
    • 当浏览器第一次接收到服务器返回资源的 Etag 值后,其会把这个值存储起来,并在下次访问该资源时通过携带 If-None-Match 请求首部发送给服务器验证该资源有没有过期。

缓存新鲜度 🔗

缓存新鲜度 = max-age || (expires - date)

当 max-age 存在时缓存新鲜度等于 max-age 的秒数,是一个时间单位,就像保质期为 6 个月一样。当 max-age 不存在时,缓存新鲜度等于 expires - date 的值,expires 我们应该已经熟悉,它是一个绝对时间,表示缓存过期的时间,那么下面主要介绍下首部字段 date

缓存使用期 🔗

缓存使用期 = 响应使用期 + 传输延迟时间 + 停留缓存时间

  • response_time(浏览器缓存收到响应的本地时间)是电脑客户端缓存获取到响应的本地时间,而 date_value(响应首部 date 值) 上面已经介绍过是服务器创建报文的时间,两者相减与 0 取最大值。

  • Age 表示推算资源创建经过时间,可以理解为源服务器在多久前创建了响应或在代理服务器中存贮的时长,单位为秒。

传输延迟时间 🔗

传输延迟时间 = response_time - request_time

停留缓存时间 🔗

停留缓存时间 = now - response_time

协商缓存 🔗

浏览器启用协商缓存的前提是强缓存失效,但是反过来强缓存失效并不一定导致浏览器启用协商缓存。

last-modified 弊端 🔗

  • last-modified 最小单位为秒, 资源的修改时间毫秒级别,那么服务器会误认为该资源仍然是没有修改的,这便导致了资源无法在浏览器及时更新的现象。
  • 资源的实质内容并没有被修改,那么服务器还是会返回最新的 last-modified 时间值

eTag生成原理 🔗

  • 使用文件大小和修改时间
  • 使用文件内容的 hash 值和内容长度

弱ETag会在字段值最开始处附加 W/

ETag: W/“29322-09SpAhH3nXWd8KIVqB10hSSz66”

启发式缓存对于缓存新鲜度计算公式

缓存新鲜度 = max(0,(date - last-modified)) * 10%

根据响应报头中 date 与 last-modified 值之差与 0 取最大值后取其值的百分之十作为缓存时间。

缓存方案 🔗

  • 频繁变动的资源,比如 HTML, 采用协商缓存
  • CSS、JS、图片资源等采用强缓存,使用 hash 命名

如何让 HTML 文件走协商缓存,前提得先让浏览器强缓存失效

1
2
Cache-Control: max-age=0
Last-Modified: Sat, 04 Sep 2021 08:59:40 GMT

webpack中将 chunkhash 和 contenthash 组合使用才能最大化的利用 HTTP 缓存中强缓存的优势,减少不必要的资源重复请求,提升网页的整体打开速度。

Command + Shift + R刷新页面 🔗

所有资源的请求首部都被加上了 cache-control: no-cachepragma: no-cache,两者的作用都表示告知(代理)服务器不直接使用缓存

硬性重新加载并没有清空缓存,而是禁用缓存

base64 缓存 🔗

从本质上看 base64 图片其实就是一堆字符串,其伴随着页面的渲染而加载,浏览器会对其进行解析,会损耗一定的性能。按照浏览器的“节约原则”

Base64 格式的图片被塞进 memory cache 可以视作浏览器为节省渲染开销的“自保行为”。

Nginx缓存配置 🔗

  • Access-Control-Allow-Origin表示指定允许访问的域名(白名单)

  • 同时当前端配置了 axios.defaults.withCredentials = true 时,服务端需配置 access-control-allow-credentials: true

  • 如果浏览器发起了预检请求,那么可能还需要配置 access-control-allow-methodsaccess-control-allow-headers 报头为允许的值

nginx add_header 继承问题

当且仅当当前层级上未定义任何 add_header 时,才可以从上层继承 add_header

以下配置最终只会添加 Cache-Control 首部

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
server {
    listen 80;
    location / {
        add_header Test '掘金';

        if ($request_filename ~* .*.(html|htm)$) {
            add_header Cache-Control 'no-cache';
        }
    }
}

Memory Cache 和 Disk Cache 🔗

  • JS脚本HTML 渲染阶段就被加载的,会被缓存到Memory Cache,异步加载的会被缓存到Disk Cache

  • 异步 JS 资源加载时浏览器渲染进程可能还没有结束,而进程没结束就有被存入内存的可能。

  • CSS 资源比较与众不同,其被磁盘缓存的概率远大于被内存缓存。

  • preload: 也被称为预加载,其用于 link 标签中,可以指明哪些资源是在页面加载完成后即刻需要的,浏览器会在主渲染机制介入前预先加载这些资源,并不阻塞页面的初步渲染。

  • prefetch: 则表示预提取,告诉浏览器加载下一页面可能会用到的资源,浏览器会利用空闲状态进行下载并将资源存储到缓存中。