• 前端缓存汇总



    前言

    前端缓存 一般用于缓存 一些不常修改的常量数据一些静态资源文件。大部分接口请求的数据都缓存在了服务端,方便统一管理缓存数据。

    前端做缓存的必要性:可以缓解服务端的压力,减少带宽的占用,同时也可以提升前端的查询性能。

    前端缓存可分为两大类:浏览器存储HTTP 缓存


    一、浏览器存储

    浏览器存储的分类:

    浏览器缓存与本地存储

    0、bfcache

    浏览器往返缓存–back-forward cache(bfcache)
    浏览器的 bfcache 特性

    1、WebStorage

    WebStorage提供两种类型的API:localStorage 和 sessionStorage。它们均继承自 Storage 类。

    Storage 类的主要用途:

    • 提供一种在 cookie 之外存储会话数据的途径;
    • 提供一种可以存储大量的跨会话数据的机制(不会产生跨域)。
    • 与操作 cookie 中的数据不同,由于 Storage 类型的数据不会产生跨域,所以操作它里面的数据的时候不必开启本地服务器(Wampserver)。

    Storage 类型只能存储字符串,非字符串的数据在存储之前会被转为字符串。

    Storage 类型有以下方法:

    • clear():删除所有值。
    • getItem(name):根据指定的名字 name 获取对应的值。
    • key(index):获得 index 位置处的值的名字。
    • removeItem(name):删除由 name 指定的名值对儿。
    • setItem(name, value):为指定的 name 设置一个对应的值。

    其中,getItem()、removeItem() 和 setItem() 方法可以直接调用,也可以通过 Storage 对象间接调用。删除数据的时候还可以使用 delete 操作符直接删除。另外,还可以使用 length 属性来判断有多少名值对儿存放在 Storage 对象中。

    在使用 Storage 类型时,建议使用它的方法而不是属性来访问数据,以免某个键会意外重写该对象上已存在的成员

    对 Storage 对象进行任何修改都会在 document 对象上触发 storage 事件,这个事件的 event 对象有以下 4 个属性:

    • domain:发生变化的存储空间的域名。
    • key:设置或删除的键名。
    • newValue:如果是设置值,则是新值;如果是删除键,则是 null。
    • oldValue:键被更改之前的值。

    可以这样侦听 storage 事件:

    EventUtil.addHandler(document, "storage", function(event){
        var event = EventUtil.getEvent(event);
        alert("当前 Storage 对象的域名是:" + event.domain);
    });
    
    • 1
    • 2
    • 3
    • 4


    上述代码中用到的 EventUtil 事件处理程序,详情请戳:js 跨浏览器事件处理程序脚本

    但是测试发现,storage 事件并未触发,怎么回事呢?

    原来触发 storage 事件是有条件的,必须满足一下条件:

    • 同一浏览器打开了两个同源页面;
    • 其中一个页面修改了localStorage;
    • 另一个网页注册了这个事件。

    下面就来介绍,Storage 类的两个实例对象:localStorage 和 sessionStorage。

    (1)、sessionStorage 对象

    Cookie、Session 和 Token 三种维持用户会话状态的机制

    sessionStorage 对象是 Storage 类型的一个实例,拥有 Storage 的所有属性和方法。

    sessionStorage 对象用来:存储特定的某个会话的数据。如果需要跨越会话存储数据,请选择 globalStorage 或 localStorage 对象。

    sessionStorage 对象的特点:

    • 页面刷新不会影响 sessionStorage 对象中的数据;除 IE 之外,其他浏览器即使崩溃了,重启后也不会影响 sessionStorage 对象中的数据。
    • 因为 sessionStorage 对象绑定于某个服务器会话,所以当文件在本地运行时 sessionStorage 是不可用的。
    • 存储在 sessionStorage 对象中的数据只能由最初给该对象存储的页面能够访问到,所以对多页面应用有限制。

    操作 sessionStorage 对象里存储的数据:

    // 存储数据
    sessionStorage.name02 = "Caocao";
    sessionStorage.setItem("name01", "Zhangfei");
    // 获取数据
    console.log(sessionStorage.name01); // Caocao
    console.log(sessionStorage.getItem("name02")); // Zhangfei
    // 删除数据
    delete sessionStorage.name01;
    sessionStorage.removeItem("name02");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    (2)、localStorage 对象

    localStorage 对象是 Storage 类型的一个实例,拥有 Storage 的所有属性和方法。

    localStorage 对象用来:持久保存客户端的数据(数据保留到通过 JavaScript 删除或者是用户清除浏览器缓存)。

    localStorage 对象的特点:

    • 必须遵从同源策略(同协议、同域名、同端口),否则会跨域。

    操作 localStorage 对象中的数据:

    // 存储数据
    localStorage.name01 = "Liuibang";
    localStorage.setItem("name02", "Zhangliang");
    // 获取数据
    console.log(localStorage.name01); // Liuibang
    console.log(localStorage.getItem("name02")); // Zhangliang
    // 删除数据
    delete localStorage.name01;
    localStorage.removeItem("name02");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    localStorage 同时存取储多条数据:

    // 存
    const data = {
        a: 111,
        b: "333",
        c: false,
    };
    localStorage.setItem("data", JSON.stringify(data));
    
    // 取
    const data = JSON.parse(localStorage.getItem("data"));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2、Cookie

    请参见这篇文章:Cookie 的使用

    (1)、cookie 与 sessionStorage、localStorage 的对比

    cookiesessionStoragelocalStorage
    生命周期可以自己设置,默认到浏览器关闭页面关闭就结束除非自己删除,否则一直存在。
    存储类型只能存储字符串只能存储字符串只能存储字符串
    大小<4KB5MB5Mb
    保存地址客户端客户端客户端
    安全性
    是否存在跨域存在跨域不会跨域存在跨域

    Cookie:

    • 用来存储客户端的 HTTP 状态信息。
    • 同一个域名下的 cookie 是共享的。不利于 http 性能的提升,而且不同域名间会产生跨域。
    • 数量受限,大小受限。不同的浏览器对 cookie 都有各自的数量限制,且每个 cookie 只能存储 4KB 大小的数据。
    • 可以设置有效期。关闭浏览器后,没有设置有效期的 cookie 会被清掉,设置了有效期的 cookie 会继续生效,直到过期时自动清掉。

    sessionStorage(会话存储):

    • 用于临时保存同一窗口(或标签页)的数据。在关闭窗口后这些数据会自动删除。
    • 只能存储字符串。
    • 不会产生跨域。
    • 同步存储。
    • 大小受限,最多只能存储 5M 。

    localStorage(本地存储):

    • 用来持久保存客户端的数据。只要不人为删除数据会一直在。
    • 只能存储字符串。
    • 不会产生跨域。
    • 同步存储。
    • 大小受限,最多只能存储 5M 。

    3、IndexedDB

    IndexedDB 的特点:

    • 键值对存储:在对象仓库中,数据以“键值对”的形式保存,每一个数据都有对应的键名,键名是独一无二的,不能有重复,否则会抛出一个错误。
    • 支持二进制储存:可存储字符串、二进制数据(ArrayBuffer 对象和 Blob 对象)。
    • 支持异步存储:。
    • 储存空间大:不同浏览器的上限不同。
    • 支持事务:IndexedDB 支持事务,这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。
    • 同域限制: IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
    • 览器兼容性不好。

    IndexedDB 的使用场景:

    • 数据超过了 5M,建议使用 IndexedDB 存储在本地。
    • 数据在 5M 以内,建议使用 localStorage 存储在本地。

    与 localstorage 相比,indexedDB 的优势在于:IndexedDB 允许储存大量数据,提供查找接口,还能建立索引。这些都是 LocalStorage 所不具备的。

    就数据库类型而言,IndexedDB 不属于关系型数据库(不支持 SQL 查询语句),更接近 NoSQL 数据库。

    4、WebSql

    WebSql 于 2010 年被 W3C 废弃,但主流浏览器都已经有了相关的实现。
    现在官网已经停止维护 webSQL 了,转为维护 indexedDB。

    WebSql 是本地数据存储方案之一。

    WebSQL 更准确的说是 WebSQL DB API,它是一种操作本地数据库的网页 API 接口,通过 API 可以完成客户端数据库的操作。

    当我们使用 WebSQL 的时候,可以方便地用 SQL 来对数据进行:增、删、改、查。而这些浏览器客户端,比如 Chrome 和 Safari 会用 SQLite 实现本地存储,微信就采用了 SQLite 作为本地聊天记录的存储。

    WebSQL 的简单使用
    WebSQL:如何在H5中存储一个本地数据库?

    5、H5 webapp 的离线缓存

    HTML5 的应用缓存(简称 app cache)是专门为开发离线 web 应用而设计的,确保离线时资源可用。目前,Application Cache 方案已经从 W3C 标准里移除了。

    建议使用 PWA 离线缓存 方案来实现。


    二、HTTP 缓存

    HTTP 缓存是通过设 置 HTTP Header 来实现的。

    HTTP 缓存分类:

    • 强缓存:在缓存期间不需要请求。
      • Pragma
      • Cache-Control
      • Expires
    • 协商缓存:如果缓存过期了,就需要发起请求验证资源是否有更新。当浏览器发起请求验证资源时,如果资源没有做改变,那么服务端就会返回 304 状态 码,并且更新浏览器缓存有效期。
      • ETag/If-Not-Match
      • Last-Modified/If-Modified-Since

    强缓存 与 协商缓存的对比:

    • 共同点:都是从客户端缓存中读取资源。
    • 区别是:强缓存不会发请求,协商缓存会发请求

    1、强缓存

    强缓存指的是:先不向服务器发送请求,而是直接从缓存中读取资源。

    • 若缓存有效,则状态码是 200,并且 Size 显示 from disk cache(硬盘缓存)或 from memory cache(内存缓存)。
    • 若缓存已过期,才会向服务器发送请求。

    强缓存的 2 种实现方式:利用 Expires 或者 Cache-Control 这两个 HTTP Response Header 实现的,它们都用来表示资源在客户端缓存的有效期。

    • Expires:Expires 属性是一个绝对时间。
    • Cache-Control:Cache-Control 属性是一个相对时间,即一个过期时间大小,与协商缓存一样。可以更加准确地判断文件内容是否被修改,避免由于时间篡改导致的不可靠问题。

    HTTP 强缓存的设置方式有多种,按照优先级从大到小依次是:S-maxage > max-age > Expires > 预估过期时间

    (1)、Expires(一个绝对时间)

    在这里插入图片描述
    Expires 属性是一个绝对时间。

    Expires 缓存的弊端:

    • 受限于本地时间,如果修改了本地时间,可能会造成缓存失效。
    • 到期时间由服务端生成的,但是客户端时间可能跟服务端时间有误差,这就会导致缓存命中的误差。

    (2)、Cache-Control(一个相对时间)

    HTTP 1.1 的版本,使用 Cache-Control 替代了 Expires 做浏览器的强制缓存。

    在这里插入图片描述
    Cache-Control 属性是一个相对时间,即一个过期时间大小,与协商缓存一样。可以更加准确地判断文件内容是否被修改,避免由于时间篡改导致的不可靠问题。

    Cache-Control 可以在 请求头 或者 响应头 中设置,并且可以组合使用多种指令:

    • 常见的取值有:private、public、no-cache、max-age,no-store。
    • 默认取值为:private
    • Cache-Control 多种指令的含义:
      • private: 客户端可以缓存。
      • public: 客户端和代理服务器都可缓存。
      • max-age=xxx: 缓存的内容将在 xxx 秒后失效,需要重新请求。
      • s-max-age=xxx: 缓存的内容将在 xxx 秒后失效,需要重新请求。
      • no-cache: 需要使用协商缓存来验证缓存数据。
      • no-store: 所有内容都不会缓存(强制缓存、协商缓存都不会触发)。
      • max-stale=xx:xxx秒内即使缓存过期,也使用该缓存。
      • min-fresh=xx: 希望在xx秒内获取获取最新响应。

    用 Cache-Control 实现 强缓存 的流程如下:

    • 当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上 Cache-Control,Cache-Control 中设置了过期时间大小;
    • 浏览器再次请求访问服务器中的该资源时,会先通过请求资源的时间与 Cache-Control 中设置的过期时间大小,来计算出该资源是否过期,如果没有,则使用该缓存,否则请求服务器;
    • 服务器再次收到请求后,会再次更新 Response 头部的 Cache-Control。

    2、协商缓存

    协商缓存指的是:与服务端协商之后,通过协商结果来判断是否使用本地缓存。

    协商缓存的 2 种实现方式:

    • Last-Modified/If-Modified-Since:可以基于请求头部中的 If-Modified-Since 字段与返回头部中的 Last-Modified 字段实现——基于时间实现
    • ETag/If-None-Match:也可以基于请求头部中的 If-None-Match 字段与返回头部中的 ETag 字段来实现——基于唯一标识实现——可以更加准确地判断文件内容是否被修改,避免由于时间篡改导致的不可靠问题。

    优先级:ETag/If-None-Match > Last-Modified/If-Modified-Since

    这 2 种协商缓存的 实现流程 如下:

    • 当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上 ETag 唯一标识,这个唯一标识的值是根据当前请求的资源生成的;
    • 当浏览器再次请求访问服务器中的该资源时,会在 Request 头部加上 If-None-Match 字段,该字段的值就是 Response 头部加上 ETag 唯一标识;
    • 服务器再次收到请求后,会根据请求中的 If-None-Match 值与当前请求的资源生成的唯一标识进行比较,如果值相等,则返回 304 Not Modified,如果不相等,则在 Response 头部加上新的 ETag 唯一标识,并返回 200 状态码和请求的资源;
    • 如果浏览器收到 304 的请求响应状态码,则会从本地缓存中加载资源,否则更新资源。

    二者的区别:

    • ETag/If-None-Match:准确度更高,Last-Modified 只能精确到秒级。
    • Last-Modified/If-Modified-Since:性能更好(不一定,当资源被重复生成,而内容不变 Etag 更适合)。

    可以将 Last-Modified 与 ETag 是一起使用——服务器会优先验证 ETag,一致的情况下,才会继续比对 Last-Modified,最后才决定是否返回 304。

    (1)、Last-Modified / If-Modified-Since(资源最后修改时间)

    Last-Modified(资源最后修改时间):是该资源文件最后一次更改时间,由服务器生成,并在 response header 里返回给客户端。

    当我们第一次发出请求时,Last-Modified 由服务器返回。例如:

    Last-Modified: Fri, 23 Jul 2017 01:47:00 GMT
    
    • 1

    同时,浏览器会将这个值保存起来,下一次发送请求时,放到 request headr 里的 If-Modified-Since 里。服务器在接收到后也会做对比:

    • 如果相同,就说明该资源没有被修改过,命中协商缓存,返回状态码 304,通知客户端继续使用缓存资源。
    • 如果不相同,就说明资源被修改过,返回状态码 200,以及最新资源。

    客户端发送的这个字段一般有两种:

    • If-Modified-Since: Last-Modified-value:该字段告诉服务器如果客户端传来的最后修改时间和服务器上的一致,直接返回 304 状态码即可,当前各大浏览器均是使用该字段来向服务器传递保存的 Last-Modified 的值。如果时间不一致的话,服务器会返回所有的这个资源并返回 200 状态码。
    • If-Unmodified-Since: Last-Modified-value:该字段告诉服务器如果客户端传来的最后修改时间和服务器上的不一致,则直接返回 412 状态码(先决条件不成立——首部字段 If-Unmodified-Since 或 If-None-Match 规定的先决条件不成立)。

    Last-Modified 的弊端,比如:

    • 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;
    • 一些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);
    • 一些服务器不能精确的得到文件的最后修改时间。

    为解决上面这些问题,HTTP 新增了 ETag 字段来标注资源的唯一性。

    (2)、Etag / If-None-Match(资源的唯一标识)

    Etag(资源的唯一标识):ETag 是资源的唯一标识,由服务器生成,并在 response header 里返回给客户端。

    当我们第一次发出请求时,ETag 由服务器返回。例如:

    ETag: W/"5ce-164c641f628"
    
    • 1

    同时,浏览器会将这个值保存起来,下一次发送请求时,放到 request headr 里的 If-None-Match 里。服务器收到请求后,将 If-None-Match 的值与被请求资源的标签进行比对:

    • 如果相同,就说明该资源没有被修改过,命中协商缓存,返回状态码 304,通知客户端继续使用缓存资源。
    • 如果不相同,就说明资源被修改过,返回状态码 200,以及最新资源。

    客户端发送的这个字段一般有两种:

    • If-None-Match: ETag-value:告诉服务端如果 ETag 没匹配上需要重发资源数据,否则直接回送304 和响应报头即可。(当前各浏览器均是使用的该请求首部来向服务器传递保存的 ETag 值)。
    • If-Match: ETag-value:该字段告诉服务器如果客户端传来的 Etag 值跟服务器上的不一致,则直接返回 412 状态码(先决条件不成立——首部字段 If-Unmodified-Since 或 If-None-Match 规定的先决条件不成立)。

    3、强缓存 与 协商缓存一起使用

    强缓存 与 协商缓存 最好是配合在一起用,争取最大化的减少请求,利用缓存,节约流量

    浏览器缓存过程(强缓存 与 协商缓存一起使用):

    • 浏览器第一次加载资源,服务器返回200,浏览器将资源文件从服务器上请求下载下来,并把response header及该请求的返回时间(要与Cache-Control和Expires对比)一并缓存;
    • 下一次加载资源时,先比较当前时间和上一次返回200时的时间差,如果没有超过Cache-Control设置的max-age,则没有过期,命中强缓存,不发请求直接从本地缓存读取该文件(如果浏览器不支持HTTP1.1,则用Expires判断是否过期);
    • 如果时间过期,服务器则查看header里的If-None-Match和If-Modified-Since ;
    • 服务器优先根据Etag的值判断被请求的文件有没有做修改,Etag值一致则没有修改,命中协商缓存,返回304;如果不一致则有改动,直接返回新的资源文件带上新的Etag值并返回 200;
    • 如果服务器收到的请求没有Etag值,则将If-Modified-Since和被请求文件的最后修改时间做比对,一致则命中协商缓存,返回304;不一致则返回新的last-modified和文件并返回 200。

    三、按缓存位置区分浏览器缓存

    无论是强缓存还是协商缓存,资源缓存的位置是不同的。常见的比如:from memory cache 和 from disk cache。

    按缓存位置可以将浏览器缓存分为以下 4 种,按照优先级从大到小依次是:Service Worker > Memory Cache > Disk Cache > Push Cache

    如果以上四种缓存都没有命中的话,那么只能发起请求来获取资源了。

    1、Service Worker

    开源实验室 已启用 Service Worker,现在只要你访问过的文章,在浏览器二次访问均可离线访问。
    PWA 就是基于 service Worker 缓存实现的。

    在这里插入图片描述

    service Worker 的缓存与浏览器其他内建的缓存机制不同,它可以让我们自由控制缓存
    哪些文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。

    service Worker 的特点:

    • 借鉴了 Web Worker
    • 传输协议必须是 HTTPS。
    • 可以自由的控制缓存哪些文件、如何匹配读取缓存。
    • 且缓存是持续性的。

    当 Service Worker 没有命中缓存的时候,我们需要去调⽤ fetch 函数获取数据。也就是说,如果我们没有在 Service Worker 命中缓存的话,会根据缓存查找优先级去查 找数据。但是不管我们是从 Memory Cache 中还是从网络请求中获取的数据,浏览器都会显示我们是从 Service Worker 中获取的内容。

    【推荐阅读】
    Service Worker:让网页无网络也能访问

    2、Memory Cache——内存缓存

    在这里插入图片描述

    Memory Cache 也就是内存中的缓存,读取内存中的数据肯定比磁盘快。但是内存缓存虽然读取高效,可是缓存持续性很短,会随着进程的释放⽽释放。 ⼀旦我们关闭 Tab 页面,内存中的缓存也就被释放了。

    Memory Cache 的特点:

    • 读取效率高,但是持续时间短,会随着进程的释放而释放。
    • 几乎所有的请求资源都能进入 memory cache,比如:通过 preload 和 prefetch 预加载的资源。
    • 在从 memory cache 读取缓存时,浏览器会忽视 Cache-Control 中的一些 max-age、no-cache 等头部设置,除非设置了 no-store 这个头部设置。

    3、Disk Cache——硬盘缓存

    在这里插入图片描述

    Disk Cache 也就是存储在硬盘中的缓存,读取速度慢点,但是什么都能存储到磁盘中, 比之 Memory Cache 胜在容量和存储时效性上。

    Disk Cache 的特点:

    • 持续时间长,是实际存在于文件系统中的缓存。
    • 比内存缓存慢,但是优势在于存储容量大。

    在所有浏览器缓存中, Disk Cache 覆盖⾯基本是最⼤的。它会根据 HTTP Herder 中的字段判断哪些资源需要缓存,哪些资源可以不请求直接使用,哪些资源已经过期需要重新请求。并且即使在跨站点的情况下,相同地址的资源⼀旦被硬盘缓存下来,就不会再次去请求数据。

    4、Push Cache(了解)

    Push Cache(推送缓存)是 HTTP/2 中的内容,当以上三种缓存都没有命中时,它才会被使用。它只在会话(Session)中存在,一旦会话结束就被释放,并且缓存时间也很短暂,在 Chrome 浏览器中只有 5 分钟左右,同时它也并非严格执行HTTP头中的缓存指令。

    Push Cache 的特点:

    • 所有的资源都能被推送,并且能够被缓存,但是 Edge 和 Safari 浏览器支持相对比较差。
    • 可以推送 no-cache 和 no-store 的资源。
    • 一旦连接被关闭,Push Cache 就被释放。
    • 多个页面可以使用同一个HTTP/2的连接,也就可以使用同一个Push Cache。这主要还是依赖浏览器的实现而定,出于对性能的考虑,有的浏览器会对相同域名但不同的tab标签使用同一个HTTP连接。
    • Push Cache 中的缓存只能被使用一次。
    • 浏览器可以拒绝接受已经存在的资源推送。
    • 你可以给其他域名推送资源。

      【推荐阅读】
      再谈ServerPush,Push or Not Push
      HTTP/2 push is tougher than I thought

    四、如何设置“不使用”缓存

    • Cache-Control 设置为:
    Cache-Control: no-cache, no-store, must-revalidate
    
    • 1
    • Expires 设为当前时间之前。
    • 在引用js、css文件的url后边加上 ?+Math.random()。例如:
    <script type=“text/javascript” src=/js/test.js?+Math.random()></script> 
    
    • 1
    • 设置html页面不让浏览器缓存的方法:
    <meta http-equiv="pragma" content="no-cache"> 
    <meta http-equiv="Cache-Control" content="no-cache, must-revalidate"> 
    <meta http-equiv="expires" content="Wed, 26 Feb 1997 00:00:00 GMT">
    
    • 1
    • 2
    • 3
    • 在用 Ajax 发起请求的时候设置请求头 cach: false

    五、刷新对缓存的影响

    • 正常刷新(地址栏访问):强制缓存 和 协商缓存都有效。
    • 手动刷新(F5 刷新):强制缓存失效、协商缓存有效。
    • 强制刷新(ctrl + F5 强制刷新):强制缓存 和 协商缓存都失效。




    【参考文章】
    浏览器缓存原理总结
    前端浏览器缓存知识梳理
    浏览器缓存看这一篇就够了
    彻底理解浏览器的缓存机制
    彻底弄懂前端缓存
    理解 Web 缓存
    设计一个无懈可击的浏览器缓存方案:关于思路,细节,ServiceWorker,以及HTTP/2
    「面试题」简述浏览器缓存是如何控制的

    关于网络协议中HTTP协议
    HTTP 缓存
    浅谈HTTP缓存
    一文读懂http缓存(超详细)
    http缓存详解( 直接看图,超易懂🤗 )

    浏览器数据库 IndexedDB 入门教程

  • 相关阅读:
    【深度学习】数据准备-pytorch自定义图像分割类数据集加载
    如何快速使用proteus【硬件课程设计】
    san.js源码解读之工具(util)篇——nexttick函数
    巨详细Linux安装MySQL
    ip大小比较的方法
    RabbitMQ消息的重复消费问题
    【DRAM存储器十五】DDR介绍-关键技术之DLL和prefetch
    作为程序员,如何刚入职公司快速接手项目,如何独自调试老项目
    HLS攻城拔寨之—数组优化
    第67章 完整定义nopCommerce Jquery DataTable插件之初始化查询表单
  • 原文地址:https://blog.csdn.net/mChales_Liu/article/details/127986732