前言
关于IndexedDB
,之前有一些博主已经出过一些文章了,写的都很好,也推荐大家去看看
我们知道,现在大部分的前端面试都喜欢搞一些并不太常见的问题,于是前端内存
在今年问的开始多了起来,那么既然说到前端内存了,不免会去说webstorage
,但是webstorage
已经被问烂了,那么面试就会选择问不那么普遍的IndexedDB
这里我们不去关注别的,例如Web Storage
,我们就来说IndexedDB
我想带着我最开始学习它的思维,带着大家直观感受一下IndexedDB
:什么是IndexedDB,IndexedDB和websql的区别,IndexedDB需要写sql吗等,通过抽象的问题来进行循序渐进地了解
好,那我们开始吧
什么是IndexedDB
注:这里的
RDBMS
是指关系型数据库
MDN
给的定义是这样的,比较抽象,但是我们可以简单理解
IndexedDB
是客户端存储的一种方式,这种方式是一种数据库
的方式,并且是非关系型数据库
,既然是数据库了,那么它更适合存储大量的数据,并且有高效的查询方式
而对比之下webstorage
是简单键值对的存储方式,简单,而且存储量较少
说到数据库这里,我觉得可以说一下websql
,因为这个老的方案听起来更像和数据库
有关
websql和IndexedDB的区别
这里咱们稍微了解一下websql
,websql
是在IndexedDB
之前就有的,就像他的名字一样,它也是一种数据库形式的内存方式
但是它是需要写sql的,它引入了一组使用 SQL 操作客户端数据库的 API
-
三个核心方法
openDatabase
:使用数据库或新建数据库来创建数据库对象transaction
:允许我们根据情况控制事务提交或回滚executeSql
:这个方法用于执行真实的 SQL 查询
js
// 打开或创建数据库
var db = openDatabase('mydb', '1.0', 'My Database', 2 * 1024 * 1024);
// 创建表
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS users (id unique, name, email)');
});
// 插入数据
db.transaction(function (tx) {
tx.executeSql('INSERT INTO users (id, name, email) VALUES (?, ?, ?)', [1, 'shaka', 'shaka@virgo.com']);
});
// 查询数据
db.transaction(function (tx) {
tx.executeSql('SELECT * FROM users', [], function (tx, result) {
var rows = result.rows;
for (var i = 0; i < rows.length; i++) {
console.log('ID: ' + rows[i].id + ', Name: ' + rows[i].name + ', Email: ' + rows[i].email);
}
});
});
// 更新数据
db.transaction(function (tx) {
tx.executeSql('UPDATE users SET name = ? WHERE id = ?', ['laka', 1]);
});
// 删除数据
db.transaction(function (tx) {
tx.executeSql('DELETE FROM users WHERE id = ?', [1]);
});
就像这样
需要知道是websql就是异步的
,不会阻塞JavaScript线程,从而保持页面的响应性,所以作为websql的进阶版IndexedDB也是异步的
其实我觉得这就像非关系型数据库MongoDB 一样,非关系型数据库慢慢崛起,而且似乎和前端更为密切,所以IndexedDB
也会如此发展
IndexedDB特点
说了这么多,咱们总的说一下IndexedDB的特点,并对特殊的带上解释
- 存储量大
- 键值对存储模型:IndexedDB采用
键值对的存储模型
,其中每个存储对象都有一个唯一的键和对应的值。 - 支持事务操作
- 支持索引:IndexedDB
支持创建索引
,以便在数据存储中更快地进行查询和排序。通过创建索引,可以提高数据检索的性能。 - 支持异步。
- 同源:IndexedDB 受到
同源限制
,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库
关于IndexedDB怎么用的,其实比较繁琐
但是我们大致可以分这几步
- 打开数据库
- 创建对象存储空间
- 启动事务
- 执行数据操作
js
// 打开或创建数据库
const request = indexedDB.open('myDatabase', 1);
// 定义数据库版本升级时的操作
request.onupgradeneeded = function(event) {
const db = event.target.result;
// 创建对象存储空间
const objectStore = db.createObjectStore('users', { keyPath: 'id' });
// 创建索引
objectStore.createIndex('name', 'name', { unique: false });
};
// 数据库打开成功后的回调函数
request.onsuccess = function(event) {
const db = event.target.result;
// 启动事务,并指定操作的对象存储空间
const transaction = db.transaction(['users'], 'readwrite');
const objectStore = transaction.objectStore('users');
// 添加数据
const user = { id: 1, name: 'shaka', email: 'shaka@virgo.com' };
const addUserRequest = objectStore.add(user);
addUserRequest.onsuccess = function() {
console.log('添加成功');
};
addUserRequest.onerror = function() {
console.error('添加失败');
};
// 查询数据
const getUserRequest = objectStore.get(1);
getUserRequest.onsuccess = function() {
const user = getUserRequest.result;
console.log('User:', user);
};
getUserRequest.onerror = function() {
console.error('获取失败');
};
// 提交事务
transaction.oncomplete = function() {
db.close();
};
};
request.onerror = function() {
console.error('数据库打开失败');
};
我们不重点讨论这种方式,如果想了解具体api
或者有需要的话可以去MDN
看一下
现在一般用的解决方案是官方都推荐的一个库localForage
localForage
localForage
是现在比较常用的一种indexedDB
的解决方案,并且pinia
就可以管理localForage
关于localForage的使用方式,我就不在这里放代码了,因为在掘金已经有一定的文章了,这是我觉得较清晰,也很不错的文章,当然,还有别的优秀的文章,就不一一列举了
有使用的方式,降级处理,踩坑等,我觉得都蛮有用也蛮有意思的~
结尾
我觉得IndexedDB是一个很有意思的点,可以更好地让你了解前端存储,甚至是浏览器
对于localForage,没有过多的介绍,但是如果大家感兴趣的话,可以带着大家走一下源码,或者自己手写一个简单版用来熟悉知识点
其实前端存储是我面试的时候被问到的点,经过今年的很多次面试,我越发觉得今年的面试题并不是常规的八股,会有一些较少数人关注到的知识点
我觉得IndexedDB在这些知识点当中是有意思并且实用的,所以分享给大家
其实IndexedDB还有一些别的有意思的东西,比如存储到用户的哪个文件夹,在你找文件的过程中你还会看到别的有意思的东西,例如历史记录存储啦等等。。所以我觉得带着兴趣去学习,会发现更多的点,并且学的更好,大家加油吧~