避免主线程卡顿的关键是分离读、算、渲:事务要短小快,读写分离+内存缓存,索引匹配查询模式,CPU密集任务交Web Worker处理。

避免主线程卡顿,关键不是“少用 IndexedDB”,而是不让它的读写操作堵住 UI 线程。IndexedDB 本身是异步 API,但若使用不当——比如在事务里塞同步计算、在主线程反复开库、或把大量数据处理逻辑绑在 success 回调里——照样会拖慢页面响应。
事务要短、小、快
一个 write 事务如果耗时超过 100ms,用户就能感知卡顿。实际项目中常见问题包括:
- 在单个事务里批量写入 5000 条以上记录,尤其带索引更新时,容易触发磁盘 I/O 峰值
- 事务回调中执行格式化、过滤、状态映射等 JS 计算,把本该后台做的活儿又拉回主线程
- 未显式调用 transaction.abort() 或未正确处理 error 事件,导致事务长时间挂起、阻塞后续操作
读写分离 + 内存缓存兜底
高频读场景(如搜索联想、状态映射)别每次都查库。做法很直接:
实现 Markdown↔ HTML 互转,支持导出 PDF,用于用户请求的文档格式转换。
- 首次加载时用 IndexedDB 全量读取结构化数据(如订单状态码表、用户分类标签),转成 Map 或 Set 存内存
- 后续查找直接走内存,O(1) 完事;仅当数据变更时,再异步更新 IndexedDB
- 对超大结果集(如 10 万行主表),不全量读,改用游标分页 + limit 控制单次加载量
索引设计必须匹配查询模式
没走索引的查询≈全表扫描,十万条数据遍历一次轻松 200ms+。验证是否命中索引的方法很简单:
- 打开 Chrome DevTools → Application → IndexedDB → 点开数据库 → 查看 “Indexes” 列表,确认你要用的字段已建索引
- 查询时明确传入 indexName,例如 objectStore.index('status_time'),而不是只用 objectStore.openCursor()
- 多条件筛选优先建复合索引(如 status + createdAt),避免多个单字段索引叠加失效
大任务交给 Web Worker 处理
IndexedDB 不支持 Worker 直接访问,但可以拆解流程:
- 主线程只负责发起请求、传递参数、接收结果;数据读取由主线程完成(用 async/await)
- 把读出的数组发给 Web Worker,让它做排序、过滤、聚合等 CPU 密集型操作
- Worker 处理完后把结果发回,主线程只做轻量渲染(如更新虚拟滚动列表)
- 这样 IndexedDB 的 I/O 和 JS 计算完全错开,主线程始终有空档响应滚动、输入等交互
本质上,IndexedDB 卡顿很少是它自己慢,大多是“不该在主线程干的活儿,被塞进了它的回调里”。把读、算、渲三层切开,它就只是个安静的本地数据库。


















