1. 概念
浏览器存储:是指浏览器提供的一种本地存储数据的机智,包括: Cookie
、WebStorage
、IndexedDB
。
前端持久优化存储:通过JavaScript 在客户端进行数据持久化存储的方式,包括 LocalStores
、IndexedDB
、File API
等
特性 | Cookie | LocalStorage | SessionStores | IndexedDB | |
---|---|---|---|---|---|
数据生命周期 | 由服务器生成,可以设置过期时间;前端采用和js-cookie等组件也可以生成 | 除非被清理,否则一直存在;浏览器关闭也会保存在本地 | 刷新依然存在,页面关闭就清理,不支持跨页面交互 | 除非被清理,否则一直存在 | |
数据存储大小 | 4K | 5M | 5M | 不限制 | |
与服务端通信 | 每次都会携带在请求的header中,对于请求性能有影响;同时由于请求中都带着,容易出现安全问题 | 不参与 | 不参与 | 不参与 | |
特点 | 字符串键值对在本地存储 | 字符串键值对在本地存储 | 字符串键值对在本地存储 | IndexedDB | 是一个非关系型数据库(不支持通过SQL语句操作)。可以存储大量数据,提供接口来查询,还可以建立索引,这些都是其他存储方案无法提供的。 |
2、Cookie
Cookie
设计之初不是用来做本地存储的,而是用来弥补 HTTP
在状态管理上的不足。HTTP
协议是一个无状态的协议,客户端向服务器发请求,服务器返回响应,故事就这样结束了,但是下次发送请求如何让服务器知道你是谁呢?这种情况下就产生了 Cooike
。Cookie
本质上是浏览器里面存储的文本文件,内部以键值对的方式存储,向同一个域名下发送请求,都会携带相同的 Cookie
,服务器拿到 Cookie
进行分析,就能拿得到客户端的状态。它可以设置过期时间,用于在客户端和服务器端传递数据,由于每次携带 Cookie
信息,可能导致网络开销增加,并且存在安全问题,所以不适合存储大量数据。Cookie
本职工作并不是本地存储,而是“维持状态”,HTTP
是无状态的,HTTP
协议本身不对请求响应之间的通信状态保存。Cookie
过期等配置Cookie
分为:Session Cookie
和持久型 Cookie
,Cookie
设置中有个 HttpOnly
参数,前端浏览器使用 document.cookie
是读取不到 HttpOnly
类型的 Cookie
的,被设置为 HttpOnly
的 Cookie
记录只能通过 HTTP
请求头发送到服务端进行读写操作,这样就避免了服务器的 Cookie
记录被 JavaScript
修改,保证了服务器验证 Cookie
的安全性。Cookie
的内容主要包括:名字、值、过期时间、路径、域。路径和域一起构成 Cookie
的作用范围。若不设置过期时间,则表示这个 Cookie
的生命周期为浏览器会话时间,关闭浏览器窗口,Cookie
就消失。
这种生命周期为浏览器会话期的 Cookie
被称为会话Cookie
。会话Cookie
一般不存在硬盘上面而是保存在内存里。若设置了过期时间,浏览器就会把 Cookie
保存在硬盘上,关闭后再次打开浏览器,这些 Cookie
仍然有效,知道超过设定的过期时间,存储在硬盘上的 Cookie
可以在不同的浏览器进进程中共享,比如两个窗口。而对于保存在内存中的 Cookie
,不同的浏览器有不同的处理方式。
// 设置 Cookie
function setCookie(name, value, days) {
let expires = "";
if (days) {
const date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + value + expires + "; path=/";
}
// 读取 Cookie
function getCookie(name) {
const nameEQ = name + "=";
const ca = document.cookie.split(";");
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while(c.charAt(0) === " ") {
c = c.substring(1, c.length);
}
if (c.indexOf(nameEQ) === 0) {
return c.substring(nameEQ.length, c.length);
}
}
return null;
}
// 删除 Cookie
function deleteCookie(name) {
setCookie(name, "", -1)
}
// 使用
// 设置Cookie 有效期 7 天
setCookie("username", "john_doe", 7);
console.log(cookie); // "username-john_doe; expires= o4 Aug 2023 14:47:16“ GMT: path=/"
// 读取Cookie
const username = getCookie("username");
console.log(username) // "john_doe"
// 删除Cookie
deleteCookie("username")
Cookie
的作用是用来做状态存储的,但是有缺陷:
- 容量小:
Cookie
的体积上限4KB
,只能存储少量的信息。 - 性能差:
Cookie
紧跟域名,不管域名下的某个地址需不需要Cookie
,请求都会携带上完整的Cookie
,随着请求的增多,其实会造成巨大的性能浪费,因为请求携带了很多不必要的内容。 不安全:由于
Cookie
以纯文本的形式在浏览器和服务器中传递,很容易被截获,然后进行一系列的修改,在Cookie
的有效期内重新发送给服务器。在HttpOnly
为false
时,Cookie
信息能直接被JS
脚本来读取。3、Session
Session
是一种服务器端的机制,服务器使用类似于散列表的结构(也可能就是使用散列表)来保存信息,当程序需要为某个客户端的请求创建一个Session
时,服务器首先检查这个客户端的请求里是否已经包含了一个session
标识(sessionID)
,如果已经包含了说明以前已经为此客户端创建过session
,服务器就按照sessionID
把这个session
检索出来使用(检索不到就会新创建一个),如果客户端请求不包含sessionID
, 则为此客户端创建一个session
,而且生成相关联的sessionID
,sessionID
的值应该是一个既不重复,又不容易被找到的规律以仿造的字符串,这个sessionID
将被本次响应中返回给客户端保存。
总结:
- 服务器端存储:
session
是服务器端的一种机制,用于在服务器存储用户会话数据,服务器会为每一个用户创建一个session
,并在客户端保存一个对应的sessionID
。 - 生命周期:
session
的生命周期由服务器管理,可以设置session
的过期时间,当用户长时间不活动或者超过时间,session
会被销毁。
Cookie
和 Session
对比
cookie
存放在浏览器上,session
存放在服务器上cookie
不是很安全,可以分析存放本地的cookie
进行cookie
欺骗session
会在一定时间内保存在服务器上,当访问增多时,会占用你服务器的性能- 单个
cookie
保存的数据不能超过 4K,cookie
的数量也有限制通常是20个 - 建议:将登录等重要信息存放在
session
上,其他信息如果在每个请求中携带,可以放在cookie
中,剩下的信息本地化缓存在Web Storage
中。
4、Web Storage
Web Storage
包括 localStorage
和 sessionStorage
,是HTML5
新增的浏览器存储机制,他们在浏览器端存储数据,不会随着请求发送到服务器,不会增加网络开销,localStorage
存储的数据没有过期时间,只能手动清除或者网站清除,sessionStorage
的数据用户关闭页面或者浏览器的时候被清除,适用于临时存储。
4.1、localStorage
localStorage
有一点和 Cookie
一样,就是针对一个域名,在同一个域名下,会存储相同的一段。它可以存储大量的数据,不会过期,保留在客户端。单个 localStorage
的大小受限, 可以利用 iframe
的方式使用多个域名来突破单个页面下 localStorage
存储数据的最大限制。
注:
浏览器多个标签页打开同一个域名时,localStorage
内容是共享的,可以监听事件 storage
来做一致性操作响应处理。
例:
标签页一:通过某种行为修改localStorage
中某个属性值,然后数据接口依赖该属性值。
标签页二:由于localStorage
标签页之间共享,导致标签页二数据不准确。
操作方式
接下来我们具体看看如何操作 localStorage:
const obj = { name: "sanyuan", age: 18 };
localStorage.setItem("name", "sanyuan");
localStorage.setItem("info", JSON.stringify(obj));
接着进入相同的域名时就能拿到响应的值:
const name = localStorage.ageItem("name");
const info = JSON.parse(localStorage.getItem("info"));
从这里可以看出,localStorage
其实存储的都是字符串,如果存储其他类型的数据,需要调用JSON.stringify()
方法,用 JSON.parse
来解析成对象。
应用场景
利用 localStorage
的较大容量和持久特性,可以利用 localStorage
存储一些内容稳定的资源,比如官网的 logo
,或者存储 Base64
格式的图片资源等。
Cookie 和 localStorage 比较
localStorage
的内容上限为5M
,相比于Cookie
的4k
大大增加。当然这个5M
是针对一个域名的,因此对于一个域名时持久存储的。- 只存在客户端,默认不参与与服务器通信。这样就很好地避免了
Cookie
带来的性能问题和安全性。 - 接口封装,通过
localStorage
暴露在全局,并通过它的setItem
和getItem
等方法进行操作,很方便。
4.2、sessionStorage
sessionStorage
、localStorage
、cookie
都是在浏览器端存储的数据,其中,sessionStorage
的概念很特别,引入了一个 ”浏览器窗口“
的概念,sessionStorage
是在同源的同窗口(tab中),始终存在的数据。也就是说只要这个浏览器窗口没有关闭,即使刷新页面或者进入同源的另一个页面,数据仍然存在。关闭窗口后, sessionStorage
被销毁,同时 ”独立“
的打开的不同窗口,即使是用一页面,sessionStorage
对象也是不同的。
临时存储
很多时候数据只需要在用户浏览一组页面期间使用,关闭窗口后数据就可以丢弃了,这种情况使用 sessionStorage
很方便。
sessionStorage 和 localStorage 相同点:
- 容量上限都是
5M
- 只存在客户端,默认不参与服务端通信
- 接口封装,除了
sessionStorage
名字有所变化,存储放射式、操作方式都和localStorage
一样。
但 sessionStorage
和 localStorage
有一个本质的区别,那就是前者只是会话级别的存储,并不是持久化存储。会话结束,也就是页面关闭,这部分 sessionStorage
清空掉了。
操作方式:
// 存储
sessionStorage.setItem("name", "sanyuan");
// 取出
sessionStorage.getItem("name");
// 清除
sessionStorage.clear();
应用场景
- 可以用它对表单数据进行维护,将表单信息存储在里面,可以保证页面即使刷新也不会让之前的标点信息丢失。
可以用它存储本次浏览记录,如果关闭页面后不需要这些记录,用 sessionStorage 比较合适。事实上微博就采取了这样的存储方式。
5、IndexedDB
IndexedDB
是运行在浏览器中的 非关系型数据库,为大型数据的存储提供了接口。本质上是数据库,不是和WebStorage
的5M
一个量级,理论上讲这个容量是没有上限的。
IndexedDB的存储空间(所有访问的网站总和)为磁盘可用空间的 50%,或根据浏览器的设定分配;
IndexedDB 的特性,除了拥有数据库本身的特性,比如 支持事务,存储二进制数据:
- 键值对存储:内部采用 对象特征 存放数据,在这个对象仓库中数据采用键值对的方式存储
- 异步操作:数据库的读写属于
I/O
操作,浏览器中对异步I/O
提供了支持。 - 受同源策略限制,无法跨域访问数据库。
- 它是
NoSQL
的,不需要我们去写一些特定的SQL
语句来对数据库操作,数据形式使用的json
。 - 一个数据库中可以包含多种对象集合,相对于
SQL
数据库来说就是多个表;在一个域名下,还可以有多个数据库。但是不能跨域访问其他域的数据库。
另外一方面,用 localStorage
只能保存字符串,如果是其他的类型,那就必须用 JSON.stringify
来转换为字符串之后保存,而 IndexedDB
则可以直接保存。此外,还具备 DBMS
的常用功能,遍历、筛选等。
indexedDB 出现的意义
- 前端存储,已经有了
localStorage
和Cookies
, 但是他们都是比较简单的技术,而IndexedDB
提供了类似数据库风格的数据存储和使用方式。 Cookies
只能是字符串,储存空间小,每次HTTP
接受和发送都会传递Cookies
数据,它会占用额外流量。localStorage
是用key-value
键值模式存储数据,想让localStorage
存储对象,你需要借助JSON.stringify()
能将对象变成字符串形式,在用JSON.parse()
将字符串还原成对象,当存储的数据庞大时,这就不是最佳实践方案了,localStorage
就是专门为小数量数据设计的,他的api
设计为同步。IndexedDB
很合适存储大量数据,他的API
是异步调用的,IndexedDB
使用索引存储数据,各种数据库操作放在事务中执行,IndexedDB
支持简单的数据类型,它比localStorage
强大,API
也相对复杂,对于简单的数据,还是使用localStorage
,API
相对复杂,对于简单的数据,还是使用localStorage
。IndexedDB
能提供更为复杂的查询数据方式。
IndexedDB 特点
- 非关系型数据库(
NoSql
):MySQL
等数据库是关系型数据库,他们的主要特点就是数据都已一张二维表的形式存储,而IndexedDB
是非关系型数据库,主要以键值对打的形式存储数据,每一个数据记录都有对应的主键,主键是独一无二的,不能重复,否则会推出一个错误。 - 持久化存储:
cookie
、localStorage
、sessionStorage
等方式存储的是数据当我们清除浏览器缓存后,这些数据都会被清除掉,而使用IndexedDB
存储的数据则不会,除非手动删除该数据库。 - 异步操作:
IndexedDB
操作时不会锁死浏览器,用户依然可以进行其他操作,这与localStorage
形成鲜明的对比,后者是同步的,异步设计是为了防止大量数据的读写,拖慢网页的表现。 - 支持事务:
IndexedDB
支持事务(transaction
),这意味着一系列的操作步骤中,只要有一步失败了,整个事务都会取消,数据库回滚到事物发生之前的状态,不存在只改写一部分数据的情况,这和MySQL
等数据库的事务类似。 - 同源策略:
IndexedDB
同样存在同源限制,每一个数据库对应创建它的域名,网页只能访问自身域名下的数据库,而不能访问跨域的数据库。 - 存储量大:这也是 IndexedDB 不仅可以存储字符串,还可以存储二进制数据(
ArrayBuffer
对象和Blob
对象)。
操作方式:
/**
*打开数据库
*@param {object} dbName 数据库的名字
*@param {string} storeName 仓库名称
*@param {string} version 数据库的版本
*@param {object} 该函数会返回一个数据库实例
*/
function openDB(dbName, version = 1) {
return new Promise((resolve, reject) => {
// 兼容浏览器
var indexedDB =
window.indexedDB ||
window.mozIndexedDB ||
window.webitIndexedDB ||
window.msIndexedDB;
let db;
// 打开数据库,若没有则创建
const request = indexedDB.open(dbName, version);
// 数据库打开成功回调
request.onsuccess = function(event){
db = event.target.result; // 数据库对象
console.log("数据库打开成功");
resolve(db);
}
// 数据库打开失败回调;
request.onerror = function(event) {
console.log("数据库打开失败");
};
// 数据库有更新时候的回调
request.onupgradeneeded = function(event) {
// 数据库创建或者升级打的时候会触发
console.log("onupgradeneeded");
db = event.target.result; // 数据库对象;
var objectStore;
// 创建存储库
objectStore = db.createObjectStore("siggnalChat", {
keyPath: "sequenceId", // 主键
// autoIncrement: true // 实现自增
});
// 创建索引,在后面查询数据的时候可以根据索引查
objectStore.createIndex("link", "link", { unique: false });
objectStore.createIndex("sequenceId", "sequenceId", { unique: false });
objectStore.createIndex("messageType", "messageType", { unique: false });
}
})
}
我们将创建数据库的操作封装成了一个函数,并且该函数返回一个 Promise 对象, 使得在调用的时候可以链式调用,函数主要接收两个参数:数据库名称、数据库版本。函数内部主要有三个回调函数,分别是:
onsucess
:数据库打开成功或者创建成功的回调,这里我们将数据库实例返回了;onerror
: 数据库打开或者创建失败的回调;onupgradeneeded
: 当数据库版本有变化的时候会执行的函数,比如我们想创建新的存储库,就可以在该函数里面操作,更新数据库版本即可;
应用场景
IndexedDB
是异步的操作,适合存储大量数据或者需要离线访问的应用;- 数据可视化等界面,大量数据,每次请求会消耗很大性能;
- 即时聊天工具,大量消息需要存储到本地;
- 其他存储方式容量不满足时,不得已使用
IndexedDB
;
6、其他存储
WebSQL
:二维表的形式存储大量数据到客户端,但目前只有 Chrome 浏览器有;Application Cache
:通过manifest
配置文件在本地有选择性的存储;JavaScript
、css
、图片等静态资源文件的文件缓存机制,已废弃。cacheStorage
:在ServiceWorker
规范中定义的,用于保存每个ServiceWorker
声明的Cache
对象,未来可能替代Application Cache
的离线方案;Flash
缓存:主要用于Flash
,具有读写浏览器本地目录的功能;File API
:File API
允许前端通过JavaScript
读取和操作用户的本地文件,可以实现将文件存储到客户端,并在需要的时候读取和处理文件数据;
7、区别
localStorage
:- 存储量较大:
localStorage
可以存储大量的数据,通常可以存储 5MB 的数据; - 持久性:
localStorage
中的数据不会过期,除非用户手动清除或者网站清除,否则会一直保留在客户端; - 作用域:
localStorage
的作用域是整个域名,即在同一个域名下所有的页面的都可以访问同一份localStorage
数据;
- 存储量较大:
sessionStorage
:- 存储量大: 与
localStorage
一样,通常可以存储5MB
数据; - 会话级别:
sessionStorage
中的数据会在当前会话期间有效,即在用户关闭当前浏览器窗口或者标签页,数据会被清除; - 作用域:
sessionStorage
的作用域是当前窗口或者标签页,不同窗口或标签页之间无法共享数据
- 存储量大: 与
session
:- 服务器端存储:
session
是服务器端打的一种机制,用于在服务端存储用户会话数据,服务器会为没一个用户创建一个唯一的session
,并在客户端保存一个对应的session ID
。 - 生命周期:
session
的生命周期由服务器管理,可以设置session
的过期时间,当用户长时间不活动或超过过期时间,session
会被销毁;
- 服务器端存储:
cookies
:- 存储量小:
cookies
存储量较小,一般限制在4KB
左右; - 持久性:可以设置
cookies
的过期时间,可以是会话级别的,也可以是持久性的,当设置了过期时间,cookies
会在过期后被删除; - 作用域:
cookies
的作用域是整个域名,与localStorage
类似,在同一个域名下的所有页面都可以访问相同的cookies
数据;
- 存储量小:
IndexedDB
:- 存储容量大:
IndexedDB
是一种数据库,可以存储较大量的结构化数据,一般可以存储几十MB甚至几百MB的数据; - 异步操作:
IndexedDB
是异步的,操作数据时需要使用异步 API 进行处理; - 丰富的查询功能:
IndexedDB
支持复杂打的数据查询和索引,可以高效的检索和处理大量数据;
- 存储容量大:
8、总结
localStorage
和sessionStorage
是HTML5
新增的浏览器存储机制,用于在客户端存储数据;session
是服务器端的存储机制,用于在服务器存储用户会话数据;cookies
是在客户端和服务器端都可以操作的存储机制,用于存储少量数据,它可以设置过期时间,可以用于跟踪用户状态和实现记住登录功能;localStorage
、sessionStorage
、session
、cookies
是浏览器端的存储机制,用于在客户端存储数据,容量和持久性各有不同。IndexedDB
是一种高级的浏览器端数据库,存储容量大且查询效率高,但使用起来相对复杂一些,需要异步操作。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。