基础概念

  • 前端缓存主要是分为HTTP缓存和浏览器缓存。其中HTTP缓存是在HTTP请求传输时用到的缓存,主要在服务器代码上设置;而浏览器缓存则主要由前端开发在前端js上进行设置。

缓存 - 图1

  • 对于一个数据请求来说,可以分为发起网络请求、后端处理、浏览器响应三个步骤。浏览器缓存可以帮助我们在第一和第三步骤中优化性能。比如说直接使用缓存而不发起请求,或者发起了请求但后端存储的数据和前端一致,那么就没有必要再将数据回传回来,这样就减少了响应数据。

    缓存过程分析

  • 浏览器与服务器通信的方式为应答模式,即是:浏览器发起HTTP请求 – 服务器响应该请求。那么浏览器第一次向服务器发起该请求后拿到请求结果,会根据响应报文中HTTP头的缓存标识,决定是否缓存结果,是则将请求结果和缓存标识存入浏览器缓存中。

  • 浏览器每次发起请求,都会先在浏览器缓存中查找该请求的结果以及缓存标识。
  • 浏览器每次拿到返回的请求结果都会将该结果和缓存标识存入浏览器缓存中。

简单的过程如下图:
缓存 - 图2

强制缓存

  • 强制缓存就是向浏览器缓存查找该请求结果,并根据该结果的缓存规则来决定是否使用该缓存结果的过程,强制缓存的情况主要有三种,
    • 不存在该缓存结果和缓存标识,强制缓存失败,则直接想服务器发起请求(跟第一次发起请求一直)。缓存 - 图3
    • 存在该缓存结果和缓存标识,但该结果已失效,强制缓存失效,则使用协商缓存缓存 - 图4
    • 存在该缓存结果和缓存标识,且该结果尚未失效,强制缓存生效,直接返回该结果。缓存 - 图5
  • 当浏览器向服务器发起请求时,服务器会将缓存规则放入HTTP响应报文的HTTP头中和请求结果一起返回给浏览器,控制强制缓存的字段分别 ExpiresCache-Control ,其中 Cache-Control 优先级比 Expires 高。
    • Expires 是HTTP/1.0控制网页缓存的字段,其值为服务器返回该请求结果缓存的到期时间,即再次发起该请求时,如果客户端的时间小于Expires的值时,直接使用缓存结果。到了HTTP/1.1, Expire 已经被 Cache-Control 替代,原因在于 Expires 控制缓存的原理是使用客户端的时间与服务端返回的时间做对比,那么如果客户端与服务端的时间因为某些原因(例如时区不同;客户端和服务端有一方的时间不准确)发生误差,那么强制缓存则会直接失效,这样的话强制缓存的存在则毫无意义。
    • Cache-Control 在HTTP/1.1中, Cache-Control 是最重要的规则,主要用于控制网页缓存,主要取值为:
      • public :所有内容都将被缓存(客户端和代理服务器都可缓存)
      • private :所有内容只有客户端可以缓存,Cache-Control的默认取值
      • no-cache :客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
      • no-store :所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
      • max-age = xxx (xxx is numeric):缓存内容将在xxx秒后失效
  • 缓存存放的位置有两种,分别为 from memory cachefrom disk cache
    • from memory cache 代表使用内存中的缓存,特点是响应速度快,但有时间限制
    • from disk cache 则代表使用的是硬盘中的缓存,速度比内存慢,需要 I/O操作 读取并解析缓存内容,
    • 浏览器读取缓存的顺序为 memory –> disk –> 服务器请求
  • 在浏览器中,浏览器会在 **js和图片** 等文件解析执行后直接存入内存缓存中,那么当刷新页面时只需直接从内存缓存中读取(from memory cache);而 **css文件** 则会存入硬盘文件中,所以每次渲染页面都需要从硬盘读取缓存(from disk cache)。

    协商缓存

  • 协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,主要有以下两种情况:

    • 协商缓存生效,返回304

缓存 - 图6

  • 协商缓存失效,返回200和请求结果结果

    1. ![](https://cdn.nlark.com/yuque/0/2021/webp/2474868/1621402729588-99c9d5fc-de0c-4fa3-9c6f-bb26c15d2e3a.webp#height=568&id=uCRxI&originHeight=568&originWidth=768&originalType=binary&ratio=1&size=0&status=done&style=none&width=768)
  • 协商缓存的标识也是在响应报文的HTTP头中和请求结果一起返回给浏览器的,控制协商缓存的字段分别有: Last-Modified / If-Modified-SinceEtag / If-None-Match ,其中 Etag / If-None-Match 的优先级比 Last-Modified / If-Modified-Since 高。
    • Last-Modified / If-Modified-Since
      • Last-Modified 是服务器响应请求时,返回该资源文件在服务器最后被修改的时间
      • If-Modified-Since 则是客户端再次发起该请求时,携带上次请求返回的 Last-Modified 值,通过此字段值告诉服务器该资源上次请求返回的最后被修改时间。服务器收到该请求,发现请求头含有 If-Modified-Since 字段,则会根据 If-Modified-Since 的字段值与该资源在服务器的最后被修改时间做对比,若服务器的资源最后被修改时间大于 If-Modified-Since 的字段值,则重新返回资源,状态码为200;否则则返回304,代表资源无更新,可继续使用缓存文件
    • Etag / If-None-Match
      • Etag 是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成)
      • If-None-Match 是客户端再次发起该请求时,携带上次请求返回的唯一标识 Etag 值,通过此字段值告诉服务器该资源上次请求返回的唯一标识值。服务器收到该请求后,发现该请求头中含有 If-None-Match ,则会根据 If-None-Match 的字段值与该资源在服务器的 Etag 值做对比,一致则返回304,代表资源无更新,继续使用缓存文件;不一致则重新返回资源文件,状态码为200
  • 对于协商缓存,使用 Ctrl+F5强制刷新可以使得缓存无效。但是对于强缓存,在未过期时,必须更新资源路径才能发起新的请求(更改了路径相当于是另一个资源了,这也是前端工程化中常用到的技巧)


浏览器缓存

  • 本底存储小容量
    • Cookie 容量只有 4kb ,主要用于用户信息的存储, Cookie 的内容可以自动在请求的时候被传递给服务器。
      • 如果不在浏览器中设置过期时间,cookie被保存在内存中,生命周期随浏览器的关闭而结束,这种cookie简称会话cookie。如果在浏览器中设置了cookie的过期时间,cookie被保存在硬盘中,关闭浏览器后,cookie数据仍然存在,直到过期时间结束才消失。
      • 当服务器收到请求需要创建session对象时,首先会检查客户端请求中是否包含sessionid。如果有sessionid,服务器将根据该id返回对应session对象。如果客户端请求中没有sessionid,服务器会创建新的session对象,并把sessionid在本次响应中返回给客户端。通常使用cookie方式存储sessionid到客户端,在交互中浏览器按照规则将sessionid发送给服务器。如果用户禁用cookie,则要使用URL重写,可以通过response.encodeURL(url) 进行实现;API对encodeURL的结束为,当浏览器支持Cookie时,url不做任何处理;当浏览器不支持Cookie的时候,将会重写URL将SessionID拼接到访问地址后
    • LocalStorage 容量2.5MB 到 10MB 之间(各家浏览器不同)一般 5Mb , 它的数据将一直保存在浏览器内,知道用户清楚浏览器缓存数据位置
    • SessionStorage 的其他属性同 LocalStorage ,只不过它的生命周期同标签页的生命周期,当标签页被关闭时, SessionStorage 也会被清除。 ```javascript // webView需要手动开启localStorage WebSettings settings = webview.getSettings(); settings.setDomStorageEnabled(true);

localStorage.key = value // 不推荐 localStorage.setItem(“key”, value) localStorage.getItem(“site”); localStorage.removeItem(“key”) localStorage.clear() ```

  • 本底存储大容量

WebSqlIndexDB 主要用在前端有大容量存储需求的页面上,如在线编辑浏览器或者网页邮箱 。

  • WebSql 类似关系型数据库,容量不详,与浏览器有关,可能是25M,被W3C废弃,只有chrome支持,不建议使用
  • IndexDB 类似非关系型数据库,容量50M,
    • (1)键值对储存。 IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以”键值对”的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。
    • (2)异步。 IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。
    • (3)支持事务。 IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。
    • (4)同源限制 IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
    • (5)储存空间大 IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限。
    • (6)支持二进制储存。 IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象)。
      • 往返存储

往返缓存又称为BFCache,是浏览器在前进后退按钮上为了提升历史页面的渲染速度的一种策略。该策略具体表现为,当用户前往新页面时,将当前页面的浏览器DOM状态保存到bfcache中;当用户点击后退按钮的时候,将页面直接从bfcache中加载,节省了网络请求的时间。