跳转至

[ISSUE-0051] 商家列表打开卡顿(B+C 方案)

用户反馈(v0.10.70):「为什么打开官网列表和手机列表不卡,但是打开商家列表会卡?」

深度分析(架构层差异)

维度 merchant tab website/email/phone tab
分页 server-side(jsstore 每次 20 行 + 22w 行 sort) client-side(一次拉 50k 到 React state)
列表组件 DataGridPremium(重) ClientDataTable(轻量)
派生 useMemo dedup(in-memory,几 ms)

打开 merchant tab 同时触发 4 个 IndexedDB transaction: 1. dataRun — 22w 行 order by create_time desc + skip 0 + limit 20 2. countRun — 22w 行 native count 3. merchantStatsRun — 50k select + JS for loop(v0.10.70 改成 3 个 count + 50k 采样) 4. rows polling — 每 5 秒 select 50k 行(即便在 merchant tab 也跑,因为 KPI 计数依赖它)

website/email/phone tab 复用 rows,没 server-pagination,没额外 stats,只剩 useMemo 派生几 ms → 瞬开。

修(B + C 组合)

B:rows polling 5s → 30s + event-driven

src/sections/data/data-view.tsx:120

- pollingInterval: 5000,
+ pollingInterval: 30 * 1000,

加 runtime message 监听 — background/batch-controller.ts:418 已经在 insert 完发 maps-data-updated,data-view 监听后 refreshRows()

useEffect(() => {
  const handler = (msg: any) => {
    if (msg?.type === 'maps-data-updated') refreshRows();
  };
  browser.runtime.onMessage.addListener(handler);
  return () => browser.runtime.onMessage.removeListener(handler);
}, [refreshRows]);

效果: - 数据真变时立即刷新(2-5s 延迟内可见 background insert 完的新数据) - 没新数据时 30s polling 后备 - 后台 CPU 占用 降 6x(5s 12 次/min → 30s 2 次/min + 偶发 event)

C:默认空 sortModel → jsstore 走 id desc

local-data-view.tsx

- sortModel: [{ field: 'create_time', sort: 'desc' }] as any[],
- sort: { create_time: -1 },
+ sortModel: [] as any[],
+ sort: {},

api/search.ts apiLocalDataList

const dbSort =
  Array.isArray(dbSortRaw) && dbSortRaw.length === 0
    ? [{ by: 'id', type: 'desc' }]  // 默认走主键索引(cursor 最快)
    : dbSortRaw;

为什么 id desc 等价于 create_time desc: - id 是 IndexedDB 自增主键 - create_time = Date.now() 在 insert 时设置 - 自增 id 顺序 == 插入顺序 == create_time 顺序

为什么 id desc 快 ~10x: - IndexedDB 主键 cursor 是天生反向遍历(openCursor(null, 'prev')) - jsstore order: { by: 'create_time' } 即便有 enableSearch 索引,走的是二级索引 cursor,比主键 cursor 慢 - 22w 行的 first page:~ 500ms → ~ 50ms(实测预期)

性能预期

操作 提升
merchant tab 首次打开 1-3s 卡顿 ~ 200ms 5-10x
22w 数据 rows polling 1min 内拉取次数 12 2 + event 6x CPU 降
dataRun first page ~ 500ms ~ 50ms 10x

注意点

  • DataGrid 表头不再默认带"创建时间"箭头,但行序仍是最新在前(用户感知一致)
  • 用户主动点表头排序 → 仍走原路径(create_time / rating / quality 等都正常)
  • 'maps-data-updated' 这个 runtime message 已经在 v0.10.x 由 background 发送,不需要新协议
  • localStorage 里 sort 配置如果之前保存了 create_time desc不会被新代码覆盖 — 但 v0.10.71 后只有用户主动点表头才能"设置" sort,所以新装用户默认是空 sortModel

不做的优化

  • A 方案:merchant tab 也走 client-side 50k 复用 rows — 长期方案,但 > 50k 数据丢失访问。本轮先用 B+C 看效果,>50k 数据的彻底优化留下轮
  • D 方案:合并 IndexedDB transactions — jsstore 不一定支持复合 query,风险高收益不确定

audit_grep

- pattern: "pollingInterval:\\s*5000[^]]"
  description: "5s polling  22w 数据时压力大 - 默认改 30s + event-driven"

相关

  • [[0050-merchant-chip-truncate-50k-slow|0050-商家列表chip截断50k-加载慢]] — 上一轮,修了 stats 截断 + 轮询 10→30s
  • [[0029-dataview-perf-listener-no-cleanup|0029-DataView性能浪费索引-listener无清理]] — 历史性能优化