From dbdb2e2959b2db55e7e2ec4428c08e4e5340f760 Mon Sep 17 00:00:00 2001 From: tisonhuang Date: Sun, 1 Mar 2026 18:05:47 +0800 Subject: [PATCH] perf(export): prioritize active tab counts and avoid full-list warmup --- electron/services/chatService.ts | 21 ++++++++++++++++++ src/pages/ExportPage.tsx | 37 +++++++++++--------------------- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/electron/services/chatService.ts b/electron/services/chatService.ts index 15d42d0..fed5bbe 100644 --- a/electron/services/chatService.ts +++ b/electron/services/chatService.ts @@ -198,6 +198,7 @@ class ChatService { private sessionTablesCache = new Map>() private readonly sessionTablesCacheTtl = 300000 // 5分钟 private sessionMessageCountCache = new Map() + private sessionMessageCountHintCache = new Map() private sessionMessageCountCacheScope = '' private readonly sessionMessageCountCacheTtlMs = 10 * 60 * 1000 @@ -369,6 +370,7 @@ class ChatService { if (!connectResult.success) { return { success: false, error: connectResult.error } } + this.refreshSessionMessageCountCacheScope() const result = await wcdbService.getSessions() if (!result.success || !result.sessions) { @@ -462,6 +464,14 @@ class ChatService { lastSenderDisplayName: row.last_sender_display_name, selfWxid: myWxid }) + + if (typeof messageCountHint === 'number') { + this.sessionMessageCountHintCache.set(username, messageCountHint) + this.sessionMessageCountCache.set(username, { + count: messageCountHint, + updatedAt: Date.now() + }) + } } // 批量拉取 extra_buffer 状态(isFolded/isMuted),不阻塞主流程 @@ -824,6 +834,16 @@ class ChatService { const cached = this.sessionMessageCountCache.get(sessionId) if (cached && now - cached.updatedAt <= this.sessionMessageCountCacheTtlMs) { counts[sessionId] = cached.count + continue + } + + const hintCount = this.sessionMessageCountHintCache.get(sessionId) + if (typeof hintCount === 'number' && Number.isFinite(hintCount) && hintCount >= 0) { + counts[sessionId] = Math.floor(hintCount) + this.sessionMessageCountCache.set(sessionId, { + count: Math.floor(hintCount), + updatedAt: now + }) } else { pendingSessionIds.push(sessionId) } @@ -1511,6 +1531,7 @@ class ChatService { if (scope === this.sessionMessageCountCacheScope) return this.sessionMessageCountCacheScope = scope this.sessionMessageCountCache.clear() + this.sessionMessageCountHintCache.clear() } private async collectSessionExportStats( diff --git a/src/pages/ExportPage.tsx b/src/pages/ExportPage.tsx index a2305b8..9b704c8 100644 --- a/src/pages/ExportPage.tsx +++ b/src/pages/ExportPage.tsx @@ -237,9 +237,8 @@ const timestampOrDash = (timestamp?: number): string => { } const createTaskId = (): string => `task-${Date.now()}-${Math.random().toString(36).slice(2, 8)}` -const MESSAGE_COUNT_VIEWPORT_PREFETCH = 120 -const MESSAGE_COUNT_BACKGROUND_BATCH = 90 -const MESSAGE_COUNT_BACKGROUND_INTERVAL_MS = 90 +const MESSAGE_COUNT_VIEWPORT_PREFETCH = 180 +const MESSAGE_COUNT_ACTIVE_TAB_WARMUP_LIMIT = 960 const METRICS_VIEWPORT_PREFETCH = 90 const METRICS_BACKGROUND_BATCH = 40 const METRICS_BACKGROUND_INTERVAL_MS = 220 @@ -773,7 +772,7 @@ function ExportPage() { } try { - const batchSize = pending.length > 100 ? 48 : 28 + const batchSize = pending.length > 260 ? 260 : pending.length for (let i = 0; i < pending.length; i += batchSize) { if (loadTokenAtStart !== sessionLoadTokenRef.current) return const chunk = pending.slice(i, i + batchSize) @@ -872,6 +871,16 @@ function ExportPage() { void ensureSessionMessageCounts(targets) }, [visibleSessions, ensureSessionMessageCounts]) + useEffect(() => { + if (sessions.length === 0) return + const activeTabTargets = sessions + .filter(session => session.kind === activeTab) + .sort((a, b) => (b.sortTimestamp || b.lastTimestamp || 0) - (a.sortTimestamp || a.lastTimestamp || 0)) + .slice(0, MESSAGE_COUNT_ACTIVE_TAB_WARMUP_LIMIT) + if (activeTabTargets.length === 0) return + void ensureSessionMessageCounts(activeTabTargets) + }, [sessions, activeTab, ensureSessionMessageCounts]) + useEffect(() => { const targets = visibleSessions.slice(0, METRICS_VIEWPORT_PREFETCH) void ensureSessionMetrics(targets) @@ -889,26 +898,6 @@ function ExportPage() { void ensureSessionMetrics(rangeSessions) }, [ensureSessionMessageCounts, ensureSessionMetrics]) - useEffect(() => { - if (sessions.length === 0) return - const prioritySessions = [ - ...sessions.filter(session => session.kind === activeTab), - ...sessions.filter(session => session.kind !== activeTab) - ] - let cursor = 0 - const timer = window.setInterval(() => { - if (cursor >= prioritySessions.length) { - window.clearInterval(timer) - return - } - const chunk = prioritySessions.slice(cursor, cursor + MESSAGE_COUNT_BACKGROUND_BATCH) - cursor += MESSAGE_COUNT_BACKGROUND_BATCH - void ensureSessionMessageCounts(chunk) - }, MESSAGE_COUNT_BACKGROUND_INTERVAL_MS) - - return () => window.clearInterval(timer) - }, [sessions, activeTab, ensureSessionMessageCounts]) - useEffect(() => { if (sessions.length === 0) return const prioritySessions = [