从本地加载更快:浏览器缓存

233 阅读6分钟

本地加载速度远大于网络加载速度,借助这个思路,如果我把常用数据存储在本地,不就能加快速度了吗?于是乎,浏览器缓存

什么是浏览器缓存?

浏览器从发送请求到获取响应数据的流程:

其中在的四个环节每一步都非常依赖网络性能,外加如果数据多,就非常耗时。数据的查询获取归根到底是基于数据的缓存来实现的,缓存到哪里便是一个值得思考的地方。可以是远程数据库、可以是CDN、可以是应用层、也可以是浏览器本身。

合理的应用缓存技术,可以很大程度上优化性能,浏览器缓存便是其中至关重要的一点。

核心思路:

  • 浏览器每次发送请求,都会先去浏览器的缓存区域查找有没有目标数据。
  • 如果有就用本地的,如果没有,就去服务器请求。
  • 每一次拿到返回的请求数据都会将它和缓存表示存入到浏览器缓存区域。方便下次缓存使用。

那我们着重来讨论浏览器缓存的查找机制和缓存机制。抽象到具体就是讨论:

缓存的位置和缓存的类型。


缓存位置

缓存的位置也是有分类的,有分类就代表有优先级和查找顺序。他们的优先级一般情况下如下:

内存 缓存(Memory Cache)

  • 位置:存储在内存中
  • 特点:速度最快,适用于短期缓存,只在当前会话中有效。

磁盘缓存(Disk Cache)

  • 位置:存储在硬盘上
  • 特点:速度稍慢于内存缓存,但适用于长期缓存,可在多个会话间持久化。(浏览器会自动清理)

Service Worker 缓存(Service Worker Cache)

  • 位置:存储在硬盘上,由 Service Worker 控制和管理
  • 特点:允许更精细的缓存策略和离线使用,适用于 Web 应用。

HTTP 缓存

  • 位置:包括内存缓存和磁盘缓存,根据 Cache-ControlExpires 等 HTTP 头决定缓存策略
  • 特点:强制缓存和协商缓存策略决定了缓存的使用方式。

这里对网络请求进行了监听,可见的:内存缓存速度最快,磁盘缓存用的最多。


缓存类型

除了可以根据缓存位置进行分类之外,还可以根据缓存类型进行分类。

  • 强制缓存
  • 协商缓存

强制缓存

客户端请求之后,先访问缓存数据可看缓存是否存在。如果缓存存在,直接返回,不存在则请求真的服务器,响应后在存到缓存数据库。

直接减少了网络请求数。如果考虑优化,强缓存是首选。

强制缓存通过HTTP响应头中的两个字段进行控制:

  1. Expires :

    1. 定义了资源的到期时间,是一个具体的日期和时间。浏览器会在这个时间之前使用缓存的资源,而不去请求新的资源。
    2. 例如:Expires: Wed, 21 Oct 2023 07:28:00 GMT
Expires: Wed, 21 Oct 2023 07:28:00 GMT
// 资源在指定的日期和时间之前有效。
  1. Cache-Control

更加灵活和现代的方式,使用各种指令来控制缓存行为。常见指令有:

  • max-age=<seconds>:定义资源在多少秒内有效。例如:Cache-Control: max-age=3600 表示资源在一小时内有效。
  • public:资源可以被任何缓存(包括客户端、代理服务器等)存储。
  • private:资源只能被客户端缓存,不能被代理服务器缓存。
  • no-cache:强制向服务器进行验证,即使缓存资源未过期。
  • no-store:禁止缓存,资源不会被存储。
  • must-revalidate:一旦缓存资源过期,必须向服务器验证资源的新鲜度。
  • proxy-revalidate:类似于must-revalidate,但仅对代理服务器有效。
Cache-Control: max-age=3600, public
// 资源可以在客户端和代理服务器上缓存,并且在一小时内(3600秒)有效。

优点:

  1. 减少了服务器请求
  2. 提高了加载速度

缺点

  1. 资源更新延迟:没过期就不请求新的

协商缓存

又叫对比缓存、条件请求缓存。用于确定缓存资源过期或者不确定资源是否过期的时候,与浏览器协商,确定是否使用本地资源或者从服务器获取新资源。

协商缓存主要通过两种HTTP请求头和响应头来实现:Last-Modified / If-Modified-SinceETag / If-None-Match

  1. Last-Modified / If-Modified-Since
  • Last-Modified:服务器在响应头中包含此字段,指明资源的最后修改时间。
  • If-Modified-Since:浏览器在后续请求中包含此字段,将上次获取到的Last-Modified时间发送给服务器。
  • 如果资源自上次修改以来没有发生变化,服务器返回304 Not Modified状态码,表示可以使用缓存资源;否则返回新的资源和200 OK状态码。
  1. ETag / If-None-Match
  • ETag(Entity Tag):服务器在响应头中包含此字段,给资源分配一个唯一标识符(哈希值)。
  • If-None-Match:浏览器在后续请求中包含此字段,将上次获取到的ETag值发送给服务器。
  • 如果ETag匹配,服务器返回304 Not Modified状态码,表示可以使用缓存资源;否则返回新的资源和200 OK状态码。

示例

HTTP/1.1 200 OK
Last-Modified: Wed, 21 Oct 2023 07:28:00 GMT
ETag: "5d8c72a5edda3"
// 如果初次请求服务器邢莹透返回数据包含以上信息

浏览器会缓存上面的资源,并且在后续请求种包含以下请求头:

GET /resource HTTP/1.1
If-Modified-Since: Wed, 21 Oct 2023 07:28:00 GMT
If-None-Match: "5d8c72a5edda3"
  • 如果资源没有修改,和浏览器缓存内容一样,就会返回:
HTTP/1.1 304 Not Modified

并且使用本地资源。

  • 如果资源已经修改,返回新的资源和头部信息:
HTTP/1.1 200 OK
Last-Modified: Wed, 25 Oct 2023 10:00:00 GMT
ETag: "5d8c72a5eddb4"

并且浏览器更新缓存。

优点:

  1. 对比强制缓存,资源更新及时
  2. 相对减少服务器负载

缺点

  1. 对比强制缓存增加了请求的开销:每次请求都需要与服务器验证。
  2. 实现相对复杂:需要不断维护HTTP头部字段。

强制缓存和协商缓存不同使用场景

强制缓存:

  1. 长期不变的资源:logo、字体文件等。
  2. 高频访问的资源:比如常用的JS库。

协商缓存

  1. 频繁变化的资源:实时数据、文章等内容。
  2. 大文件资源:比如视频、大图片等。