IndexedDB封装
写在前面
IndexedDB是一个基于JavaScript的面向对象数据库。目前,前端缓存方案中,Cookie 的大小不超过4KB,且每次请求都会发送回服务器;localStorage 和 sessionStorage 在 2.5MB 到 10MB 之间(各家浏览器不同),所以,需要一种新的解决方案,允许储存大量数据,提供查找接口,还能建立索引,这就是 IndexedDB 诞生的背景。
IndexedDB特点:
- 储存空间大。IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限
- 异步。针对存储量大的特点,IndexedDB的存储应当是异步进行,以免阻塞js进程
- 键值对储存。内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以"键值对"的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能重复
封装
为了贴近传统 localStorage 的操作习惯,可以封装出与之对应的api
class IndexedDBCache {
constructor(dbName, dbVersion, storeName) {
this._dbName = dbName;
this._dbVersion = dbVersion;
this._storeName = storeName;
this._db = null;
this._keyPath = '__keyName'; // 设置主键
}
/***
* 打开数据库连接
* @returns {Promise<IDBDatabase>} 打开的数据库实例
*/
initDB() {
return new Promise((resolve, reject) => {
const request = window.indexedDB.open(this._dbName, this._dbVersion);
request.onerror = (event) => reject(event.target.error);
request.onsuccess = (event) => {
this._db = event.target.result;
resolve(event.target.result)
};
// 创建或更新对象仓库
request.onupgradeneeded = (event) => {
// 获取数据库实例
const db = event.target.result;
if (!db.objectStoreNames.contains(this._storeName)) {
db.createObjectStore(this._storeName, {
keyPath: this._keyPath,
autoIncrement: true
});
}
this._db = event.target.result;
};
});
}
/** 保存数据
*
* @param {string} key
* @param {any} data
* @returns
*/
setItem(key, data) {
const transaction = this._db.transaction([ this._storeName ], 'readwrite');
const store = transaction.objectStore(this._storeName);
return new Promise((resolve, reject) => {
const request = store.put({
[this._keyPath]: key,
data
})
request.onsuccess = () => resolve(request.result);
request.onerror = (event) => reject(event.target.error);
});
}
/** 更新数据,合并原始数据
*
* @param {string} key
* @param {any} newData
* @returns
*/
updateItem(key, newData) {
const transaction = this._db.transaction([ this._storeName ], 'readwrite');
const store = transaction.objectStore(this._storeName);
return new Promise((resolve, reject) => {
const request = store.get(key);
request.onsuccess = () => {
let { data } = request.result || {};
if(this._isObject(newData) && this._isObject(data)) {
Object.assign(data, newData);
} else {
data = newData;
}
const updateRequest = store.put({
[this._keyPath]: key,
data
});
updateRequest.onsuccess = () => resolve(request.result);
updateRequest.onerror = (event) => reject(event.target.error);
};
request.onerror = (event) => reject(event.target.error);
});
}
// 获取数据
getItem( key ) {
if(!key) return Promise.resolve();
const transaction = this._db.transaction([ this._storeName ], 'readonly');
const store = transaction.objectStore(this._storeName);
return new Promise((resolve, reject) => {
const request = store.get(key);
request.onsuccess = () => {
const { data } = request?.result || {}
resolve(data)
};
request.onerror = (event) => reject(event.target.error);
});
}
// 读取所有数据
getAllData() {
const transaction = this._db.transaction([ this._storeName ], 'readonly');
const store = transaction.objectStore(this._storeName);
return new Promise((resolve, reject) => {
const request = store.getAll();
request.onsuccess = () => {
let list = request?.result?.map( i => {
const { [this._keyPath]: key, ...data } = i;
return {
...data,
[this._keyPath]: key
}
})
resolve(list)
};
request.onerror = (event) => reject(event.target.error);
});
}
// 删除数据
removeItem(key) {
const transaction = this._db.transaction([ this._storeName ], 'readwrite');
const store = transaction.objectStore(this._storeName);
return new Promise((resolve, reject) => {
const request = store.delete(key);
request.onsuccess = () => resolve(true);
request.onerror = (event) => reject(event.target.error);
});
}
// 关闭数据库
closeDB () {
this._db.close()
}
_isObject(obj) {
return Object.prototype.toString.call(obj) === '[object Object]';
}
}
使用
实例化并开启
const db = new IndexedDBCache('myDB', 1, 'myStore');
db.initDB()
存数据
由于所有操作都是异步,故该操作应在 initDB() 之后
// await db.initDB()
db.setItem ('用户', { name: '朱棣', age: 135 }).then((key) => {
console.log('添加成功,主键为:', key);
}).catch((error) => {
console.error('添加失败:', error);
});
取数据
// await db.initDB()
db.getItem('用户').then((data) => {
console.log('读取数据:', data);
}).catch((error) => {
console.error('读取失败:', error);
});
删除数据
// await db.initDB()
db.removeItem('用户').then((data) => {
console.log('删除成功');
}).catch((error) => {
console.error('删除失败:', error);
});
--- end ---

浙公网安备 33010602011771号