用indexeddb存搜索历史需建search_history仓库,设id、query、timestamp等字段及searchprefix规范化字段,对其建idx_prefix索引,用idbkeyrange.bound(query, query+'\uffff')实现毫秒级前缀查询,写入时去重更新,读取按updatedat降序且防抖限条。

用 IndexedDB 保存搜索历史,核心是建好结构、预处理关键词、加索引、用范围查询快速匹配,而不是遍历过滤。
设计对象仓库与规范化字段
创建名为 search_history 的对象仓库,主键建议用自增 id 或时间戳。每条记录至少包含:id、query(原始输入)、timestamp、updatedAt。关键一步是额外存一个规范化字段:searchPrefix,值为:
query.trim().toLowerCase().replace(/[^\w\s]/g, '')
这个字段统一大小写、剔除标点,确保前缀匹配不因格式差异漏结果。
在 searchPrefix 上建索引并实现前缀查询
对 searchPrefix 字段建立非唯一索引,名称如 idx_prefix:
objectStore.createIndex('idx_prefix', 'searchPrefix', { unique: false })
查“net”时,构造范围而非遍历:
const range = IDBKeyRange.bound(query, query + '\uFFFF')- 用该 range 在
idx_prefix索引上打开游标:index.openCursor(range) - 游标只落在以 query 开头的键上,毫秒级响应,5 万条实测 3–8ms
注意:空字符串要拦截,避免 IDBKeyRange.bound('', '\uFFFF') 扫全量。
写入时去重、更新与排序
搜索历史不是日志流,需防重复刷屏(如连续输入 “a”→“ab”→“abc”):
- 写入前先用
index.get(query)检查是否已存在相同searchPrefix - 若存在,用
put()更新updatedAt时间戳,保持最新在前 - 读取时按
updatedAt降序排列,前端可直接渲染
读取与交互优化
用户输入未完成时,不必每次触发查询:
- 输入停顿 200–300ms 后再执行游标查询(防抖)
- 限制返回最多 10–20 条,避免长列表卡顿
- 配合
AbortController支持中止上一次未完成的查询 - 前端展示时高亮匹配前缀部分(如用
span包裹),提升可读性











