前端缓存 一般用于缓存 一些不常修改的常量数据 或 一些静态资源文件。大部分接口请求的数据都缓存在了服务端,方便统一管理缓存数据。
前端做缓存的必要性:可以缓解服务端的压力,减少带宽的占用,同时也可以提升前端的查询性能。
前端缓存可分为两大类:浏览器存储 和 HTTP 缓存 。
浏览器存储的分类:
浏览器往返缓存–back-forward cache(bfcache)
浏览器的 bfcache 特性
WebStorage提供两种类型的API:localStorage 和 sessionStorage。它们均继承自 Storage 类。
Storage 类的主要用途:
Storage 类型只能存储字符串,非字符串的数据在存储之前会被转为字符串。
Storage 类型有以下方法:
其中,getItem()、removeItem() 和 setItem() 方法可以直接调用,也可以通过 Storage 对象间接调用。删除数据的时候还可以使用 delete 操作符直接删除。另外,还可以使用 length 属性来判断有多少名值对儿存放在 Storage 对象中。
在使用 Storage 类型时,建议使用它的方法而不是属性来访问数据,以免某个键会意外重写该对象上已存在的成员。
对 Storage 对象进行任何修改都会在 document 对象上触发 storage 事件,这个事件的 event 对象有以下 4 个属性:
可以这样侦听 storage 事件:
EventUtil.addHandler(document, "storage", function(event){
var event = EventUtil.getEvent(event);
alert("当前 Storage 对象的域名是:" + event.domain);
});
上述代码中用到的 EventUtil 事件处理程序,详情请戳:js 跨浏览器事件处理程序脚本。
但是测试发现,storage 事件并未触发,怎么回事呢?
原来触发 storage 事件是有条件的,必须满足一下条件:
下面就来介绍,Storage 类的两个实例对象:localStorage 和 sessionStorage。
sessionStorage 对象是 Storage 类型的一个实例,拥有 Storage 的所有属性和方法。
sessionStorage 对象用来:存储特定的某个会话的数据。如果需要跨越会话存储数据,请选择 globalStorage 或 localStorage 对象。
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");
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");
localStorage 同时存取储多条数据:
// 存
const data = {
a: 111,
b: "333",
c: false,
};
localStorage.setItem("data", JSON.stringify(data));
// 取
const data = JSON.parse(localStorage.getItem("data"));
请参见这篇文章:Cookie 的使用
cookie | sessionStorage | localStorage | |
---|---|---|---|
生命周期 | 可以自己设置,默认到浏览器关闭 | 页面关闭就结束 | 除非自己删除,否则一直存在。 |
存储类型 | 只能存储字符串 | 只能存储字符串 | 只能存储字符串 |
大小 | <4KB | 5MB | 5Mb |
保存地址 | 客户端 | 客户端 | 客户端 |
安全性 | 弱 | 强 | 强 |
是否存在跨域 | 存在跨域 | 不会跨域 | 存在跨域 |
Cookie:
sessionStorage(会话存储):
localStorage(本地存储):
IndexedDB 的特点:
IndexedDB 的使用场景:
与 localstorage 相比,indexedDB 的优势在于:IndexedDB 允许储存大量数据,提供查找接口,还能建立索引。这些都是 LocalStorage 所不具备的。
就数据库类型而言,IndexedDB 不属于关系型数据库(不支持 SQL 查询语句),更接近 NoSQL 数据库。
WebSql 于 2010 年被 W3C 废弃,但主流浏览器都已经有了相关的实现。
现在官网已经停止维护 webSQL 了,转为维护 indexedDB。
WebSql 是本地数据存储方案之一。
WebSQL 更准确的说是 WebSQL DB API,它是一种操作本地数据库的网页 API 接口,通过 API 可以完成客户端数据库的操作。
当我们使用 WebSQL 的时候,可以方便地用 SQL 来对数据进行:增、删、改、查。而这些浏览器客户端,比如 Chrome 和 Safari 会用 SQLite 实现本地存储,微信就采用了 SQLite 作为本地聊天记录的存储。
WebSQL 的简单使用
WebSQL:如何在H5中存储一个本地数据库?
HTML5 的应用缓存(简称 app cache)是专门为开发离线 web 应用而设计的,确保离线时资源可用。目前,Application Cache 方案已经从 W3C 标准里移除了。
建议使用 PWA 离线缓存 方案来实现。
HTTP 缓存是通过设 置 HTTP Header 来实现的。
HTTP 缓存分类:
强缓存 与 协商缓存的对比:
强缓存指的是:先不向服务器发送请求,而是直接从缓存中读取资源。
强缓存的 2 种实现方式:利用 Expires 或者 Cache-Control 这两个 HTTP Response Header 实现的,它们都用来表示资源在客户端缓存的有效期。
HTTP 强缓存的设置方式有多种,按照优先级从大到小依次是:S-maxage > max-age > Expires > 预估过期时间
。
Expires 属性是一个绝对时间。
Expires 缓存的弊端:
HTTP 1.1 的版本,使用 Cache-Control 替代了 Expires 做浏览器的强制缓存。
Cache-Control 属性是一个相对时间,即一个过期时间大小,与协商缓存一样。可以更加准确地判断文件内容是否被修改,避免由于时间篡改导致的不可靠问题。
Cache-Control 可以在 请求头 或者 响应头 中设置,并且可以组合使用多种指令:
用 Cache-Control 实现 强缓存 的流程如下:
协商缓存指的是:与服务端协商之后,通过协商结果来判断是否使用本地缓存。
协商缓存的 2 种实现方式:
优先级:ETag/If-None-Match > Last-Modified/If-Modified-Since
。
这 2 种协商缓存的 实现流程 如下:
二者的区别:
可以将 Last-Modified 与 ETag 是一起使用——服务器会优先验证 ETag,一致的情况下,才会继续比对 Last-Modified,最后才决定是否返回 304。
Last-Modified(资源最后修改时间):是该资源文件最后一次更改时间,由服务器生成,并在 response header 里返回给客户端。
当我们第一次发出请求时,Last-Modified 由服务器返回。例如:
Last-Modified: Fri, 23 Jul 2017 01:47:00 GMT
同时,浏览器会将这个值保存起来,下一次发送请求时,放到 request headr 里的 If-Modified-Since 里。服务器在接收到后也会做对比:
客户端发送的这个字段一般有两种:
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 的弊端,比如:
为解决上面这些问题,HTTP 新增了 ETag 字段来标注资源的唯一性。
Etag(资源的唯一标识):ETag 是资源的唯一标识,由服务器生成,并在 response header 里返回给客户端。
当我们第一次发出请求时,ETag 由服务器返回。例如:
ETag: W/"5ce-164c641f628"
同时,浏览器会将这个值保存起来,下一次发送请求时,放到 request headr 里的 If-None-Match 里。服务器收到请求后,将 If-None-Match 的值与被请求资源的标签进行比对:
客户端发送的这个字段一般有两种:
If-None-Match: ETag-value
:告诉服务端如果 ETag 没匹配上需要重发资源数据,否则直接回送304 和响应报头即可。(当前各浏览器均是使用的该请求首部来向服务器传递保存的 ETag 值)。If-Match: ETag-value
:该字段告诉服务器如果客户端传来的 Etag 值跟服务器上的不一致,则直接返回 412 状态码(先决条件不成立——首部字段 If-Unmodified-Since 或 If-None-Match 规定的先决条件不成立)。强缓存 与 协商缓存 最好是配合在一起用,争取最大化的减少请求,利用缓存,节约流量。
浏览器缓存过程(强缓存 与 协商缓存一起使用):
无论是强缓存还是协商缓存,资源缓存的位置是不同的。常见的比如:from memory cache 和 from disk cache。
按缓存位置可以将浏览器缓存分为以下 4 种,按照优先级从大到小依次是:Service Worker > Memory Cache > Disk Cache > Push Cache
。
如果以上四种缓存都没有命中的话,那么只能发起请求来获取资源了。
开源实验室 已启用 Service Worker,现在只要你访问过的文章,在浏览器二次访问均可离线访问。
PWA 就是基于 service Worker 缓存实现的。
service Worker 的缓存与浏览器其他内建的缓存机制不同,它可以让我们自由控制缓存
哪些文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。
service Worker 的特点:
当 Service Worker 没有命中缓存的时候,我们需要去调⽤ fetch 函数获取数据。也就是说,如果我们没有在 Service Worker 命中缓存的话,会根据缓存查找优先级去查 找数据。但是不管我们是从 Memory Cache 中还是从网络请求中获取的数据,浏览器都会显示我们是从 Service Worker 中获取的内容。
【推荐阅读】
Service Worker:让网页无网络也能访问
Memory Cache 也就是内存中的缓存,读取内存中的数据肯定比磁盘快。但是内存缓存虽然读取高效,可是缓存持续性很短,会随着进程的释放⽽释放。 ⼀旦我们关闭 Tab 页面,内存中的缓存也就被释放了。
Memory Cache 的特点:
Disk Cache 也就是存储在硬盘中的缓存,读取速度慢点,但是什么都能存储到磁盘中, 比之 Memory Cache 胜在容量和存储时效性上。
Disk Cache 的特点:
在所有浏览器缓存中, Disk Cache 覆盖⾯基本是最⼤的。它会根据 HTTP Herder 中的字段判断哪些资源需要缓存,哪些资源可以不请求直接使用,哪些资源已经过期需要重新请求。并且即使在跨站点的情况下,相同地址的资源⼀旦被硬盘缓存下来,就不会再次去请求数据。
Push Cache(推送缓存)是 HTTP/2 中的内容,当以上三种缓存都没有命中时,它才会被使用。它只在会话(Session)中存在,一旦会话结束就被释放,并且缓存时间也很短暂,在 Chrome 浏览器中只有 5 分钟左右,同时它也并非严格执行HTTP头中的缓存指令。
Push Cache 的特点:
Cache-Control: no-cache, no-store, must-revalidate
?+Math.random()
。例如:<script type=“text/javascript” src=“/js/test.js?+Math.random()”></script>
<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">
cach: false
。【参考文章】
浏览器缓存原理总结
前端浏览器缓存知识梳理
浏览器缓存看这一篇就够了
彻底理解浏览器的缓存机制
彻底弄懂前端缓存
理解 Web 缓存
设计一个无懈可击的浏览器缓存方案:关于思路,细节,ServiceWorker,以及HTTP/2
「面试题」简述浏览器缓存是如何控制的
关于网络协议中HTTP协议
HTTP 缓存
浅谈HTTP缓存
一文读懂http缓存(超详细)
http缓存详解( 直接看图,超易懂🤗 )