Skip to content

在前面的 webStoreage,我们知道在浏览器里其实是可以本地存放一些内容的,比如 localStorage,可以存放一些键值对,但是有很多限制,比如键值对都只能是字符串,比如一般来说 localStorage 只有 5 M 的空间(实际上这比 cookie 的最大容量大很多)。所以 localStorage 实际上只有在我们需要在用户电脑上存储少量数据的时候才会使用到。

如果我们真的要在客户端进行大容量的结构化数据存储,使用 localStorage 就不太合适了,我们可以使用 indexedDB 来进行存储。

实际上,从名字也能看出,indexedDB 本质上就是一个放在浏览器里面的数据库。

这里先介绍如何使用 indexedDB

js
const request = window.indexedDB.open("test", 1);//该方法可以连接一个数据库,数据库的名称为test,版本为1,会返回一个请求。
//注意,连接数据库本身是异步操作,所以返回一个请求对象,这个对象上有一些事件可以监听
//关于版本号:如果我连接的数据库版本号高于当前版本号,则会升级并触发upgradeneeded事件,如果我连接的数据库版本号低于当前版本号,则会触发error事件,如果版本号相同则不触发upgradeneeded事件
//实际上这也意味着版本号无法降级
request.addEventListener("success", () => {
	console.log("success");//连接成功
});
request.addEventListener("error", () => {
	console.log("error");//连接失败
});
request.addEventListener("upgradeneeded", () => {
	console.log("upgradeneeded");//数据库初始化或者版本升级的时候触发
});

这个数据库可能和传统意义上的数据库不太一样,传统意义上的数据库实际上是由一张一张表组成的,而这个数据库实际上是由键值对组成的,其实也就是一个一个数据存储对象组成。简单来说,传统数据库里面的一张表对应的就是 indexDB 中的数据存储对象。

我们可以通过 e.target.result 属性拿到数据库本身,调用这个数据库的 createObjectStore() 方法并传入一个数据存储对象的名称,就可以创建一个数据存储对象。此时我们就可以使用这个数据存储对象上的一些方法,在这个数据存储对象里面存取数据。

js
const request = window.indexedDB.open("test", 1);//该方法可以连接一个数据库,数据库的名称为test,版本为1,会返回一个请求。
//注意,连接数据库本身是异步操作,所以返回一个请求对象,这个对象上有一些事件可以监听
//关于版本号:如果我连接的数据库版本号高于当前版本号,则会升级并触发upgradeneeded事件,如果我连接的数据库版本号低于当前版本号,则会触发error事件,如果版本号相同则不触发upgradeneeded事件
//实际上这也意味着版本号无法降级
request.addEventListener("success", e => {
	console.log("success");//连接成功
});
request.addEventListener("error", () => {
	console.log("error");//连接失败
});
request.addEventListener("upgradeneeded", e => {
	console.log("upgradeneeded");//数据库初始化或者版本升级的时候触发
	const db = e.target.result;
	const store = db.createObjectStore("test");//在这个数据库上创建了一张表,表名为test
	store.add({ name: "蔡徐坤", age: 30 }, "user1");//添加数据,key为用户1,值就是第一个参数中的对象
	//创建或删除存储对象只能发生在该事件上,在其他事件我们是直接进行操作该存储对象,不能创建和删除存储对象本身。
});

如果我们后续还要进行处理,则可以在 success 事件中进行处理,为了保证数据操作的完整性,读者也可以理解为安全性,我们需要使用事务来操作这个数据库,我们可以使用数据库中的transaction 方法来创建一个事务,第一个参数传入一个数组,表示我这个事务可以操作哪些数据表,第二个参数为模式,或者说是权限,比如 readonly,readwrite,versionchange,也就是只读,可读写,版本升级。默认为只读。

从这里我们应该可以看出,事务是可以操作多个表的,我们一次只能操作一个表,所以就可以通过事务上的 objectStore() 方法传入一个表名,拿到数据表,从而对这个数据表进行各种增删改查操作。

js
request.addEventListener("success", e => {
	console.log("success");//连接成功
	const db = e.target.result;//获得数据库对象
	const transaction = db.transaction(["test"], "readwrite");//创建一个事务
	const store = transaction.objectStore("test");//获得存储对象,也就是数据库中的表
	// store.add(["唱", "跳", "rap", "篮球"], "loves");//增加数据
	// store.add(["唱", "跳", "rap", "篮球"], "loves2");//增加数据
	// store.delete("loves2");//删除数据
	// store.put({ name: "马保国", age: 70 }, "user1");//修改数据
	// store.put({ name: "蔡徐坤" }, "user100");//如果修改一个不存在的key,那么会增加
	const result = store.getAll();//获得这个表的所有数据,这个是异步操作,也是基于事件
	result.addEventListener("success", e => {
		console.log(e.target.result);//这里就可以获得所有数据
	});
	result.addEventListener("error", () => {
		console.log("error");//获取失败
	});
	const result2 = store.get("user1");//获取单个数据
	result2.addEventListener("success", e => {
		console.log(e.target.result);
	});
});

在创建数据存储对象,也就是数据表的时候,我们可以通过数据库中的 objectStoreNames 属性判断是否存在,如果存在了,那么应该阻止创建。

以笔记为镜,可以知得失