- 作者:老汪软件技巧
- 发表时间:2024-10-10 11:04
- 浏览量:
介绍
浏览器本地存储API有很多,例如:Cookie、IndexDB、WebStorage 他们都有各自的缺点,我们希望设计一套通用的本地存储API去解决这个问题。
首先我们要知道每个本地存储API的缺点:
预期的结果:
基于以上的问题能够使用的API只有 indexDB 和 localStorage,我们希望可以在现代浏览器中使用 indexDB 在老版本浏览器中使用 localStorage 进行存储数据,
遇到的问题:
它们的存储方式是不同的,例如:indexDB 需要调用 open 方法开启数据库后才开始存储操作并且所有的操作都是基于异步的,而 localStorage 只需要使用 getItem 、setItem等方法直接同步存储。
如何解决:
我们可以通过模板模式设置一个基类内部包含 getItem、setItem等方法并且要求所有操作都是异步的,让 indexDB 和 localStorage 都继承该基类去解决问题。
代码实现
设置模板:
class Template {
getItem(key){
throw new Error('必须实现 getItem 方法');
},
setItem(key,value){
throw new Error('必须实现 setItem 方法');
},
removeItem(key){
throw new Error('必须实现 removeItem 方法');
},
clear(){
throw new Error('必须实现 clear 方法');
},
getAll(){
throw new Error('必须实现 getAll 方法');
}
}
实现LocalStorage类:
class LocalStorage {
getItem(key) {
return new Promise((resolve, reject) => {
const result = localStorage.getItem(key);
try {
resolve({
status: true,
message: '获取数据成功',
data: JSON.parse(result)
});
} catch (e) {
resolve({
status: true,
message: '获取数据成功',
data: result
});
}
});
}
setItem(key, value) {
return new Promise((resolve, reject) => {
try {
localStorage.setItem(key, value);
resolve({
status: true,
message: '新增数据成功',
data: null
});
} catch (e) {
reject(e);
}
});
}
removeItem(key) {
return new Promise((resolve, reject) => {
try {
localStorage.removeItem(key);
resolve({
status: true,
message: '删除数据成功',
data: null
});
} catch (e) {
reject(e);
}
});
}
clear() {
return new Promise((resolve, reject) => {
try {
localStorage.clear();
resolve({
status: true,
message: '清除所有数据成功',
data: null
});
} catch (e) {
reject(e);
}
})
}
getAll() {
return new Promise((resolve, reject) => {
try {
const len = localStorage.length;
const items = [];
for (let i = 0; i < len; i++) {
const key = localStorage.key(i);
const value = localStorage.getItem(key);
items.push({key: value});
}
resolve({
status: true,
message: '获取所有数据成功',
data: items
})
} catch (e) {
reject(e);
}
})
}
}
实现IndexDB类
// 这个方法用于打开 indexDB 数据库并返回 Promise 对象。
function openDatabase(databaseName, version, storeName = 'store_personal') {
return new Promise((resolve, reject) => {
const request = indexedDB.open(databaseName, version);
request.onupgradeneeded = (event) => {
const db = event.target.result;
// 为数据库创建对象存储(objectStore)
const objectStore = db.createObjectStore(storeName, {
keyPath: "key",
autoIncrement: true
});
// 创建一个索引
objectStore.createIndex("key", "key", {unique: false});
};
request.onsuccess = (event) => {
resolve(event);
};
request.onerror = (event) => {
console.error(`数据库错误:${event.target.errorCode}`);
reject(event.target.errorCode);
};
});
}
class IndexDB {
constructor(databaseName,version,storeName) {
this.IDBDatabase = openDatabase(databaseName,version,storeName);
this.storeName = storeName;
}
getItem(key) {
return new Promise(async (resolve) => {
const IDBDatabase = await this.IDBDatabase; // 等待外界拿到indexDB数据库实例。
const transaction = IDBDatabase.target.result.transaction([this.storeName], 'readonly');
const objectStore = transaction.objectStore(this.storeName);
const request = objectStore.get(key);
request.onsuccess = (event) => {
resolve({
status: true,
message: '查找成功',
data: event.target.result || request.result
});
};
request.onerror = (event) => {
resolve({
status: false,
message: '查找失败',
data: event.target.error || null
});
}
});
}
setItem(key, value) {
return new Promise(async (resolve, reject) => {
const IDBDatabase = await this.IDBDatabase;
const transaction = IDBDatabase.target.result.transaction([this.storeName], 'readwrite');
const objectStore = transaction.objectStore(this.storeName);
// put方法如果之前存在则修改,否则新增。如果想要put修改生效则需要设置主键让数据库知道哪些数据是相同的。
const request = objectStore.put({key, value});
request.onsuccess = () => {
resolve({
status: true,
message: '新增成功',
data: {key, value}
})
}
request.onerror = (event) => {
resolve({
status: false,
message: '新增失败',
data: event.target.error || null
});
}
});
}
deleteItem(key) {
return new Promise(async (resolve) => {
const IDBDatabase = await this.IDBDatabase;
const transaction = IDBDatabase.target.result.transaction([this.storeName], 'readwrite');
const objectStore = transaction.objectStore(this.storeName);
const request = objectStore.delete(key);
request.onsuccess = (event) => {
resolve({
status: true,
message: '删除成功',
data: event.target.result || request.result
});
}
request.onerror = (event) => {
resolve({
status: false,
message: '删除失败',
data: event.target.error || null
});
}
});
}
clear() {
return new Promise(async (resolve) => {
const IDBDatabase = await this.IDBDatabase;
const transaction = IDBDatabase.target.result.transaction([this.storeName], 'readwrite');
const objectStore = transaction.objectStore(this.storeName);
const request = objectStore.clear();
request.onsuccess = (event) => {
resolve({
status: true,
message: '数据清除成功',
data: null
});
}
request.onerror = (event) => {
resolve({
status: false,
message: '数据清除失败',
data: event.target.error || null
});
}
});
}
getAll() {
return new Promise(async (resolve) => {
const IDBDatabase = await this.IDBDatabase;
const transaction = IDBDatabase.target.result.transaction([this.storeName], 'readwrite');
const objectStore = transaction.objectStore(this.storeName);
const request = objectStore.getAll();
request.onsuccess = (event) => {
resolve({
status: true,
message: '获取所有数据成功',
data: event.target.result || request.result
});
}
request.onerror = (event) => {
resolve({
status: false,
message: '获取所有数据失败',
data: event.target.error || null
});
}
});
}
}
根据浏览器支持情况选择对应的类:
function useStore() {
const _indexDB = new IndexDB('store', 1, 'store_personal');
const _localStorage = new LocalStorage();
const strategy = window.indexedDB !== undefined ? _indexDB : _localStorage;
return {
getItem(key) {
return strategy.getItem(key);
},
setItem(key,value) {
return strategy.setItem(key,value);
},
removeItem(key) {
return strategy.removeItem(key);
},
clear(){
return strategy.clear();
},
getAll(){
return strategy.getAll();
}
}
}