`title: IndexedDB 最佳实践与高性能查询``categories: Web 开发/前端/数据管理``keywords: IndexedDB,事务,索引,IDBKeyRange,游标,性能优化``description: 系统性梳理 IndexedDB 的模式设计、索引与范围查询、批量写入与分页、版本迁移与错误处理,并给出经过验证的代码示例与性能优化建议。`为什么选 IndexedDB结构化数据、事务支持、可创建索引与范围查询,适合离线与大数据量场景。相比 `localStorage`:异步、不阻塞主线程、容量更大、更可靠。模式与索引设计使用一个库多对象仓库:按业务域拆分 `objectStore`,避免过度耦合。键与索引:主键使用自增或显式主键;为高频查询建立索引,如 `userId`、`createdAt`。范围查询:使用 `IDBKeyRange.bound/lowerBound/upperBound` 实现时间窗或分页。事务与并发事务级别:读 `readonly`,写 `readwrite`;同一事务中批量读写减少开销。自动提交:事务在所有请求完成且事件队列清空后自动提交;失败会自动回滚。版本迁移在 `onupgradeneeded` 中创建或迁移对象仓库与索引;保证幂等(存在则跳过)。错误处理与稳定性监听 `request.onerror` 与 `db.onversionchange`;版本变化时主动关闭并提示刷新。捕获 `QuotaExceededError` 与权限错误,给出降级方案(如仅保留关键数据)。批量写入与分页查询示例function openDB(name = 'app-db', version = 1) { return new Promise((resolve, reject) => { const req = indexedDB.open(name, version); req.onupgradeneeded = () => { const db = req.result; if (!db.objectStoreNames.contains('items')) { const store = db.createObjectStore('items', { keyPath: 'id' }); store.createIndex('byCreatedAt', 'createdAt'); store.createIndex('byUserId', 'userId'); } }; req.onsuccess = () => resolve(req.result); req.onerror = () => reject(req.error); }); } async function bulkPut(db, items) { return new Promise((resolve, reject) => { const tx = db.transaction('items', 'readwrite'); const store = tx.objectStore('items'); for (const item of items) store.put(item); tx.oncomplete = () => resolve(); tx.onerror = () => reject(tx.error); tx.onabort = () => reject(tx.error); }); } async function queryByTime(db, start, end, limit = 50, afterKey) { return new Promise((resolve, reject) => { const tx = db.transaction('items', 'readonly'); const idx = tx.objectStore('items').index('byCreatedAt'); const range = start && end ? IDBKeyRange.bound(start, end) : start ? IDBKeyRange.lowerBound(start) : end ? IDBKeyRange.upperBound(end) : undefined; const result = []; let count = 0; idx.openCursor(range, 'next').onsuccess = e => { const cursor = e.target.result; if (!cursor) return resolve({ items: result, nextKey: undefined }); if (afterKey && cursor.key <= afterKey) { cursor.continue(afterKey); return; } result.push(cursor.value); count++; if (count >= limit) return resolve({ items: result, nextKey: cursor.key }); cursor.continue(); }; tx.onerror = () => reject(tx.error); }); } 性能优化建议索引覆盖查询:优先通过索引满足过滤与排序,避免全表扫描。批量写入:合并操作进单事务;大批次可分块写入(如 1k 条/事务)。游标分页:用游标+`nextKey` 取下一页,避免 `offset` 式低效分页。避免主线程阻塞:长任务放到 `Worker`,主线程仅发消息。兼容性与注意事项现代浏览器均支持 IndexedDB;隐私模式可能受限,需降级方案。键与索引必须稳定、可序列化;含 `undefined` 字段不会被持久化。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部
1.672840s