Skip to content

perf: 会话切换及大量消息渲染仍存在卡顿 #4

@MoYeRanqianzhi

Description

@MoYeRanqianzhi

问题描述

完成 Rust 后端全量计算迁移 + 前端渐进式渲染优化后,大部分场景已流畅,但以下场景仍存在 1-2 秒 可感知的卡顿:

  • 会话切换:从一个大会话切换到另一个大会话时,有明显延迟
  • 大量消息渲染:500+ 条消息的会话在 idle 扩散完成前,滚动到未渲染区域有短暂空白

当前架构

Rust 后端(已优化,不是瓶颈)

  • rayon 并行分类/转换消息
  • memchr SIMD 加速搜索
  • 内存缓存 TransformedSession

前端渐进式渲染(当前瓶颈所在)

  • useProgressiveRender hook:ref + version 计数器模式
  • 初始渲染 80 条 → idle 扩散(每批 60 条,每 250 条 flush 一次 React 重渲染)
  • 滚动 handler 使用 rAF 节流 + 二分查找视口中心

已完成的优化

提交 内容
2b836ca Rust 后端全量计算迁移 + 渐进式渲染 hook
f8f8962 移除 content-visibility: auto(与渐进式渲染冲突导致 scrollHeight 不稳定)
4fbfa0d 移除消息级 motion.div、rAF 节流 handleScroll、加大批次参数

剩余瓶颈分析

1. 会话切换时的完整重建开销

切换会话时,整个消息列表被销毁并重建:

  • React 需要卸载旧消息的所有 DOM 节点
  • 然后创建新会话的全部节点(80 条初始 + 占位符)
  • visibleMessages 从数组 A 切换为数组 B,key 全部不同,无法复用

可能的优化方向

  • 会话级缓存:缓存已渲染会话的 DOM 快照或 React 状态,切换时恢复而非重建
  • startTransition / useDeferredValue:将消息列表更新标记为低优先级过渡

2. 消息组件未 memoize

每次 version bump 触发 ChatView 重渲染时,visibleMessages.map() 对所有消息重新求值:

  • 已渲染的消息虽然 VDOM diff 后不产生 DOM 变更,但 JSX 创建 + diff 本身有成本
  • MessageBlockList / MessageContentRenderer 等子组件未用 React.memo

可能的优化方向

  • 将消息渲染抽取为 React.memo 组件,props 为 (msg, isRendered: boolean, ...)
  • 将回调函数用 useCallback 稳定化,避免 memo 失效

3. Markdown 渲染开销

每条消息的 Markdown 内容(代码块、表格等)在首次渲染时需要解析 + 生成 React 元素树。500 条消息的 Markdown 累积解析时间可能达数百毫秒。

可能的优化方向

  • Rust 端预渲染 Markdown 为 HTML 字符串,前端直接 dangerouslySetInnerHTML
  • 前端 Markdown 组件 memoize(按 text 内容 hash)

4. requestIdleCallback 的局限性

requestIdleCallback 在浏览器繁忙时可能长时间不调度,导致扩散进度停滞。

可能的优化方向

  • 混合策略:idle 优先,但超时后降级为 setTimeout(0) 保底

关键文件

  • src/hooks/useProgressiveRender.ts — 渐进式渲染 hook
  • src/components/ChatView.tsx — 消息列表渲染主体
  • src/components/MessageBlockList.tsx — 消息内容块渲染
  • src-tauri/src/services/transformer.rs — Rust 消息转换器

环境

  • Tauri v2 + React 19 + TypeScript
  • 测试设备:Windows 11
  • 典型会话大小:200-800 条消息

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions