不能用 getall() 做分页,因其会一次性加载全部数据导致内存溢出或页面卡死;应使用游标分页,通过 idbkeyrange 与 opencursor 结合按键值范围分段查询,确保高效、稳定、可续读。

为什么不能用 getAll() 做分页
getAll() 会一次性把整个 objectStore 的数据加载进内存,几千条记录就可能触发浏览器内存警告,上万条大概率卡死页面。游标分页不是“取第 N 页”,而是“从某条记录继续往后拉”,天然支持按需加载、断点续读。
常见错误现象:RangeError: Maximum call stack size exceeded(递归过深)、OutOfMemoryError(Chrome 控制台报内存不足)、页面无响应。
- 事务生命周期短:Safari 中长时间遍历易导致事务自动关闭,
transaction.oncomplete必须监听并做收尾 - 游标不可跨事件循环保存:拿到
cursor后必须在当前onsuccess回调里调用cursor.continue(),否则报InvalidStateError - 不能用
for (const item of cursor)——cursor没有[Symbol.iterator],会直接报TypeError: cursor is not iterable
用 IDBKeyRange + openCursor 实现稳定下一页
核心是记录上一页最后一条的键(cursor.key 或索引字段值),作为下一页查询的起点。这要求主键或索引字段可比较(如 number、时间戳字符串),且已建好对应索引。
假设按 createdAt 降序分页,索引名为 by_time:
const index = store.index('by_time');
// 上一页最后一条的 createdAt 是 1715678900000
const range = IDBKeyRange.upperBound(1715678900000, true); // true 表示不包含该值
const request = index.openCursor(range, 'prev'); // 'prev' 实现倒序
-
IDBKeyRange.upperBound(key, true)是关键:漏掉true会导致重复返回同一条 - 方向必须匹配排序逻辑:倒序查用
'prev',正序用'next' - 如果索引是复合的(如
["status", "createdAt"]),range必须传数组,且顺序一致
cursor.continue() 不是 skip,别传错参数
cursor.continue(key) 的作用是“seek 到 ≥ key 的下一条记录”,不是跳过前 N 条。它只适合连续分页,不适合跳转到任意页(比如直接翻到第 100 页)。
错误用法:cursor.continue(100) 想跳到第 100 条 —— 实际是 seek 到键为 100 的记录,若不存在则停在第一个 > 100 的键上。
- 首次查询用
openCursor(null, 'prev'),取完后记下cursor.key - 下一页调用
cursor.continue(lastKey),但前提是游标打开时用了相同索引和方向 - 若存在相同
createdAt的多条记录,仅靠时间戳无法唯一定位,必须拼上主键(如{ createdAt: 1715678900000, id: "abc123" })构造复合范围
复合索引与边界判断必须配套做
单纯建复合索引不够,查询时的 IDBKeyRange 必须与索引字段顺序、类型严格对齐,否则索引失效,退化成全表扫描。
例如建了 store.createIndex("by_status_time", ["status", "createdAt"]),查 status === "active" 且倒序分页:
const index = store.index('by_status_time');
const range = IDBKeyRange.bound(
['active', 1715678900000], // 下界:status=active 且 createdAt = 0(最小值)
true, // 跳过下界
false // 包含上界
);
const request = index.openCursor(range, 'prev');
- 边界为
null时,IDBKeyRange.lowerBound(['active'])可匹配所有status === "active"记录 - 游标走到末尾时,
event.target.result为null,此时应停止加载并置空“下一页”按钮 - 插入/删除操作不影响游标分页结果,但若在分页过程中修改了索引字段值,可能导致漏项 —— 这是 IndexedDB 本身限制,无法规避
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











