indexeddb分页应采用游标+上一页末尾键的游标分页法,避免offset低效遍历;支持复合索引、游标位置存储及边界判断以提升稳定性和性能。

IndexedDB 本身不支持 SQL 那样的 LIMIT 和 OFFSET,但可以通过游标(cursor)配合键范围(KeyRange)和迭代控制,实现高效、稳定的分页查询。核心思路是:**用上一页最后一条记录的主键(或索引键)作为下一页的起点,避免跳过大量数据**。
使用游标 + 上一页末尾键实现“游标分页”(推荐)
这是最健壮的分页方式,不依赖偏移量,不受插入/删除影响,性能稳定。
- 假设你按时间倒序查询,索引字段为
createdAt(number 类型时间戳),主键为id - 第一页:打开游标,从最大键开始,
direction: "prev",取前 10 条 - 获取第一页最后一条记录的
createdAt值(比如1715678900000) - 第二页:用
IDBKeyRange.upperBound(1715678900000, true)限定范围,并设direction: "prev",再取 10 条 - 注意:
true表示“不包含等于该值的项”,确保不会重复返回同一条
用 index.openCursor() + count 控制每页数量
适合简单分页场景,需手动计数,但逻辑清晰。
- 打开索引游标时传入
IDBKeyRange.bound(min, max)或IDBKeyRange.lowerBound(key)划定范围 - 在
onsuccess回调中遍历游标,用计数器限制返回条数(如if (count >= pageSize) cursor.continue(); else cursor.continue();) - 不要用
cursor.skip(n)模拟 offset —— IndexedDB 没有 skip 方法,手动跳过会严重拖慢性能
避免使用“offset 分页”的原因
模拟 OFFSET 20 LIMIT 10 在 IndexedDB 中代价极高:
- 必须从头遍历前 20 条记录,再读取后续 10 条,数据越多越慢
- 若分页过程中有新数据插入(尤其在排序字段相同的情况下),会导致漏项或重复
- 无法利用索引高效定位起始位置,失去 IndexedDB 的优势
实用小技巧
提升分页体验与可靠性:
-
复合索引优先:如需按
status+createdAt排序分页,建立复合索引store.createIndex("by_status_time", ["status", "createdAt"]) -
存储游标位置:把上一页末尾的键值(如
{ createdAt: 1715678900000, id: "abc123" })存入内存或 URL,作为下一页请求依据 -
处理边界情况:当游标无更多匹配项时,
event.target.result为null,应停止加载并提示“已到底部”











