1. 核心概念与特点
- 定义:IndexedDB 是浏览器提供的一种底层 API,用于客户端存储大量结构化数据(如 JSON 对象、文件二进制数据等)。支持高性能的索引查询、事务操作,适合复杂场景。
- 核心特性:键值存储:数据以键值对形式存储,键可自定义或自动生成。事务支持:保证数据操作的原子性和一致性。异步 API:所有操作均为异步,避免阻塞主线程。索引查询:可对数据字段创建索引,实现快速检索。大容量存储:通常支持数百 MB 至数 GB 数据(具体由浏览器决定)。
- 与 Web Storage 对比:特性Web StorageIndexedDB数据结构简单键值对结构化数据(对象/二进制)查询能力仅按键查询支持索引、范围查询、游标事务无支持原子事务容量~5MB大(通常 >250MB)适用场景简单配置/临时数据复杂应用、离线缓存
2. 基本使用流程
打开/创建数据库:使用 indexedDB.open(databaseName, version) 打开数据库,若不存在则自动创建。
const request = indexedDB.open('MyDatabase', 1);
request.onerror = (event) => {
console.error('数据库打开失败:', event.target.error);
};
request.onsuccess = (event) => {
const db = event.target.result;
console.log('数据库已打开:', db);
};
// 首次创建或版本升级时触发
request.onupgradeneeded = (event) => {
const db = event.target.result;
// 创建对象存储空间(类似表)
const store = db.createObjectStore('books', {
keyPath: 'id', // 主键字段
autoIncrement: true
});
// 创建索引(允许按书名查询)
store.createIndex('by_title', 'title', { unique: false });
};
事务操作:所有数据操作需在事务中进行,事务分为只读(readonly)和读写(readwrite)。
const transaction = db.transaction('books', 'readwrite');
const store = transaction.objectStore('books');
// 添加数据
store.add({ title: 'JavaScript权威指南', author: 'David Flanagan' });
// 查询数据(通过主键)
const getRequest = store.get(1);
getRequest.onsuccess = (event) => {
console.log('查询结果:', event.target.result);
};
// 通过索引查询
const index = store.index('by_title');
const indexRequest = index.get('JavaScript权威指南');
indexRequest.onsuccess = (event) => {
console.log('索引查询结果:', event.target.result);
};
3. 高级功能
游标遍历:使用游标遍历对象存储中的所有数据。
const cursorRequest = store.openCursor();
cursorRequest.onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
console.log('当前数据:', cursor.value);
cursor.continue(); // 继续下一个
} else {
console.log('遍历完成');
}
};
范围查询:利用 IDBKeyRange 定义查询范围。
// 查询主键在 10 到 20 之间的数据
const range = IDBKeyRange.bound(10, 20);
const rangeRequest = store.openCursor(range);
存储二进制数据:IndexedDB 支持存储 ArrayBuffer 或 Blob。
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', (event) => {
const file = event.target.files[0];
const reader = new FileReader();
reader.onload = (e) => {
const buffer = e.target.result;
store.add({ id: 1, fileName: file.name, data: buffer });
};
reader.readAsArrayBuffer(file);
});
4. 错误处理与调试
错误捕获:通过监听事务和请求的 error 事件处理异常。
transaction.onerror = (event) => {
console.error('事务失败:', event.target.error);
};
store.add(data).onsuccess = () => {
console.log('数据添加成功');
};
浏览器开发者工具:Chrome/Firefox 开发者工具中可直接查看和编辑 IndexedDB 数据(Application/Storage 面板)。
5. 使用场景
- 离线应用:缓存大量数据供离线使用(如文档编辑器、邮件客户端)。
- 复杂查询需求:需要按多个字段快速检索的场景(如商品库按价格、分类筛选)。
- 大文件缓存:存储图片、音频等二进制资源。
6. 最佳实践
封装工具库:使用轻量级库(如 Dexie.js 简化 API 调用:
const db = new Dexie('MyDatabase');
db.version(1).stores({
books: '++id, title, author' // 定义主键和索引
});
// 添加数据
await db.books.add({ title: 'Eloquent JavaScript', author: 'Marijn Haverbeke' });
// 查询数据
const books = await db.books.where('author').equals('Marijn Haverbeke').toArray();
版本迁移:在 onupgradeneeded 中处理数据库结构变更(如新增索引)。
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains('users')) {
const store = db.createObjectStore('users', { keyPath: 'email' });
store.createIndex('by_age', 'age');
}
};
性能优化:避免在单个事务中处理过多数据。使用游标分批读取大数据集。
7. 示例:简易待办事项应用
<input type="text" id="taskInput" placeholder="输入任务">
<button onclick="addTask()">添加任务</button>
<ul id="taskList"></ul>
<script>
let db;
const request = indexedDB.open('TodoDB', 1);
request.onupgradeneeded = (event) => {
db = event.target.result;
const store = db.createObjectStore('tasks', {
keyPath: 'id',
autoIncrement: true
});
store.createIndex('by_status', 'completed');
};
request.onsuccess = (event) => {
db = event.target.result;
loadTasks();
};
function addTask() {
const taskInput = document.getElementById('taskInput');
const task = {
text: taskInput.value,
completed: false,
createdAt: new Date()
};
const transaction = db.transaction('tasks', 'readwrite');
const store = transaction.objectStore('tasks');
store.add(task);
transaction.oncomplete = () => {
taskInput.value = '';
loadTasks();
};
}
function loadTasks() {
const taskList = document.getElementById('taskList');
taskList.innerHTML = '';
const transaction = db.transaction('tasks', 'readonly');
const store = transaction.objectStore('tasks');
const cursorRequest = store.openCursor();
cursorRequest.onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
const li = document.createElement('li');
li.textContent = cursor.value.text;
taskList.appendChild(li);
cursor.continue();
}
};
}
</script>
8. 安全与隐私
- 同源策略:IndexedDB 数据库仅允许同源页面访问。
- 用户隐私:用户可随时通过浏览器设置清除数据库。
- 数据加密:敏感数据建议在存储前加密(如使用 Web Crypto API)。
通过以上内容,可全面掌握 IndexedDB 的核心概念、使用方法及实际开发技巧,适用于需要处理复杂数据结构的现代 Web 应用。