IndexedDB 简介
IndexedDB
是一种浏览器内置的低层次的 API,用于在客户端存储大量结构化数据。它是一个浏览器端的数据库,允许你存储各种类型的对象,包括文件、二进制数据等,并通过键值对的方式进行快速查询。与 Web Storage(如 localStorage
和 sessionStorage
)不同,IndexedDB
可以存储大量数据并提供更丰富的查询能力,尤其适用于需要在客户端持久化存储复杂数据(如应用离线工作,或存储大量用户数据)的场景。
IndexedDB
通过对象存储(object stores)和索引(indexes)来进行数据存储和检索。对象存储可以理解为数据库表,而索引则类似于数据库中的索引,能帮助更快地查询数据。
主要特性
- 支持大数据量存储:可以存储大量数据,超出
localStorage
的限制。 - 异步API:
IndexedDB
采用异步方式进行操作,避免阻塞主线程。 - 支持事务:通过事务来保证数据操作的原子性和一致性。
- 支持键值对存储:每个对象存储可以使用键(key)来快速访问存储的对象。
使用 IndexedDB
IndexedDB
提供了包括 open()
, put()
, get()
, delete()
等方法来进行数据存取。下面是一个简单的使用例子:
// 打开或创建数据库
let db;
const request = indexedDB.open('myDatabase', 1);
// 数据库版本升级时触发
request.onupgradeneeded = function(event) {
db = event.target.result;
// 创建对象存储,类似数据库表
const objectStore = db.createObjectStore('users', { keyPath: 'id' });
objectStore.createIndex('name', 'name', { unique: false });
};
// 打开数据库成功时触发
request.onsuccess = function(event) {
db = event.target.result;
console.log('数据库打开成功');
};
// 错误处理
request.onerror = function(event) {
console.error('数据库打开失败', event);
};
IndexedDB 封装模块代码
为了方便使用 IndexedDB
,可以封装一个模块,简化常见的操作,提供统一的接口。以下是一个封装 IndexedDB
操作的例子:
class IndexedDBHelper {
constructor(dbName, version) {
this.dbName = dbName;
this.version = version;
this.db = null;
this._openDB();
}
// 打开数据库
_openDB() {
const request = indexedDB.open(this.dbName, this.version);
request.onupgradeneeded = (event) => {
const db = event.target.result;
// 可以根据需要创建对象存储
if (!db.objectStoreNames.contains('users')) {
const objectStore = db.createObjectStore('users', { keyPath: 'id' });
objectStore.createIndex('name', 'name', { unique: false });
}
};
request.onsuccess = (event) => {
this.db = event.target.result;
console.log('数据库连接成功');
};
request.onerror = (event) => {
console.error('数据库打开失败', event);
};
}
// 添加或更新数据
putData(storeName, data) {
const transaction = this.db.transaction([storeName], 'readwrite');
const objectStore = transaction.objectStore(storeName);
const request = objectStore.put(data);
request.onsuccess = () => {
console.log('数据写入成功');
};
request.onerror = (event) => {
console.error('数据写入失败', event);
};
}
// 获取数据
getData(storeName, key) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readonly');
const objectStore = transaction.objectStore(storeName);
const request = objectStore.get(key);
request.onsuccess = (event) => {
resolve(event.target.result);
};
request.onerror = (event) => {
reject('数据获取失败');
};
});
}
// 删除数据
deleteData(storeName, key) {
const transaction = this.db.transaction([storeName], 'readwrite');
const objectStore = transaction.objectStore(storeName);
const request = objectStore.delete(key);
request.onsuccess = () => {
console.log('数据删除成功');
};
request.onerror = (event) => {
console.error('数据删除失败', event);
};
}
// 查询所有数据
getAllData(storeName) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readonly');
const objectStore = transaction.objectStore(storeName);
const request = objectStore.getAll();
request.onsuccess = (event) => {
resolve(event.target.result);
};
request.onerror = (event) => {
reject('获取所有数据失败');
};
});
}
}
// 使用封装好的模块
const dbHelper = new IndexedDBHelper('myDatabase', 1);
// 在数据库打开成功后,执行操作
dbHelper.putData('users', { id: 1, name: 'Alice', age: 25 });
dbHelper.getData('users', 1).then((data) => {
console.log('获取到的数据:', data);
}).catch((error) => {
console.error(error);
});
dbHelper.getAllData('users').then((data) => {
console.log('所有用户数据:', data);
});
代码解析
_openDB()
:初始化并打开数据库,如果数据库版本有变更则触发onupgradeneeded
,可以在其中创建对象存储和索引。putData()
:向数据库中插入或更新数据,如果该键值已存在,则会更新数据。getData()
:根据指定的主键获取数据,返回一个Promise
,方便异步处理。deleteData()
:根据指定主键删除数据。getAllData()
:获取对象存储中的所有数据,同样返回一个Promise
。
总结
通过封装 IndexedDB
,我们可以更加方便地进行数据存取操作,避免了直接操作底层 API 的复杂性,并且能实现更加灵活和清晰的代码结构。IndexedDB
作为客户端存储的一个重要工具,能帮助开发者在 Web 应用中实现数据的持久化和离线访问。