使用Svelte+Vite+DexieJS离线查询渐慢问题求助及替代方案咨询
一、现有DexieJS性能问题的可能原因与修复
1. 串行查询导致的累积延迟
你的代码在循环中对每个cluster串行执行两次异步查询(taskDone和taskOngoing),每一次查询都要等待上一次完成,cluster数量越多,总耗时越长。页面反复切换后,这种累积延迟会被持续放大。
修复:改用并行查询
把循环内的两次查询用Promise.all并行发起,大幅减少等待时间:
for (const clusters of clusterQuery) { // 并行执行两个查询 const [taskDone, taskOngoing] = await Promise.all([ db.task .where("[cluster_id+status]") .anyOf([clusters.id, 1], [clusters.id, 2]) .toArray(), db.task .where({ cluster_id: clusters.id }) .toArray() ]); // ...后续逻辑 }
2. 数组操作的性能损耗
每次用tasks = [新项, ...tasks]创建新数组,会复制整个现有数组,数据量大时会频繁占用内存和CPU,导致页面卡顿。
修复:直接修改原数组
用unshift方法直接向数组头部添加元素,避免不必要的数组复制:
tasks.unshift({ cluster_id: clusters.id, count_done: taskDone.length, count_ongoing: taskOngoing.length, cluster_name: clusters.name, });
3. 内存泄漏问题
Routify切换页面时,如果组件没有清理引用,旧的tasks数组、查询结果可能残留,导致内存占用持续上升,后续查询变慢。
修复:组件销毁时清理资源
添加onDestroy钩子清空数组,释放内存:
import { onMount, onDestroy } from 'svelte'; // ...其他代码 onDestroy(() => { tasks = []; });
4. 索引有效性验证
确认你的task表schema是否正确定义了复合索引,否则之前添加的索引不会生效:
const db = new Dexie('你的数据库名'); db.version(1).stores({ cluster: 'id, name', task: 'id, cluster_id, status, [cluster_id+status]' // 确保复合索引存在 });
5. 预计算优化(可选)
如果这些统计数据不需要实时更新,可以在task数据新增/修改时,直接更新cluster表中的统计字段(比如count_done、count_ongoing),这样页面加载时只需要查询cluster表,无需遍历查询task表。
二、离线数据库替代方案推荐
1. PouchDB
你已经在尝试的方案,优势是支持离线同步(与CouchDB同步),适合需要跨设备数据同步的场景。纯本地存储场景下性能与DexieJS接近,复杂查询需用MapReduce实现,学习成本略高。
2. sql.js
基于SQLite的浏览器端实现,性能极佳,适合大数据量和复杂SQL查询场景。如果你熟悉SQL语法,它的查询效率会比DexieJS更高,但需要手动编写SQL语句,没有ORM的便利。
3. LocalForage
轻量级的IndexedDB封装,API简单易用,适合键值对存储的简单场景。但查询能力较弱,不适合复杂的关联查询。
4. Lovefield
Google开发的IndexedDB封装,提供类SQL的查询接口,性能稳定,但目前维护活跃度不如DexieJS。
内容的提问来源于stack exchange,提问作者Malik

