大数据性能
Yotsuba Gantt 将性能作为组件契约,而不是演示页特例。虚拟化负责限制渲染规模,活动预算负责约束持续动效,远程窗口事件负责把数据规模留在宿主可控范围内。
先确定数据策略
| 数据条件 | 推荐策略 |
|---|---|
| 数据已在客户端,任务量稳定 | 直接传入不可变数组,保持行列双向虚拟化 |
| 数据来自远程服务,任务量持续增长 | 按可见日期与行窗口做游标加载,并保留少量 overscan |
| 自定义任务条包含图片或复杂业务组件 | 先限制单节点成本,再评估是否需要更小的 overscan |
| 页面同时展示多个甘特图 | 只让当前可见或选中的少量元素持续动效 |
分页与虚拟化解决不同问题:分页限制客户端持有的数据量,虚拟化限制当前创建的 DOM 或 Widget 数量。大规模远程数据通常需要同时使用两者。
Vue 策略
- 行与时间列双向虚拟化,任务树、网格、任务条和依赖线共享同一个窗口。
- 滚动、表格同步、联动消息和可见范围更新按动画帧合并。
- 依赖关系使用邻接索引,只构建当前窗口附近的路径。
- 400 条以上的密集聚焦使用线性密度桶算法。
- Viewport Activity Budget 只允许少量高优先级可见元素持续动效;滚动、拖拽和页面隐藏时暂停。
dataMode="immutable"避免对大型输入做深层响应式转换。visible-range-change、totalTaskCount与taskOffset支持远程分页或游标窗口。
React 策略
- 120 行以上默认启用行虚拟化,180 个时间格以上默认启用列虚拟化。
- 任务与依赖 ID 索引通过
useMemo只在输入变化时重建。 - 依赖线只处理纵向和横向窗口内的关系。
- 多图滚动在原生滚动事件内同步,避免等待 React 状态提交。
onVisibleRangeChange可驱动远程分页,getRenderStats()可在运行时验证真实渲染量。- React 当前构建产物约 22.27 kB JS / 6.62 kB gzip,CSS 约 9.87 kB / 2.87 kB gzip。
10,000 条基准
测试日期:2026-08-01。桌面 Chromium,Vue 产品演示压力入口。
| 指标 | 结果 |
|---|---|
| DOM 节点 | 1,034 |
| 60 帧平均间隔 | 8.22 ms |
| P95 | 10.5 ms |
| 最大帧间隔 | 11.7 ms |
| Long Task | 0 |
| 静止持续动画 | 4 |
基准只能说明当前机器、浏览器和演示数据下的结果。业务侧仍应使用性能面板复核自定义插槽、图片、字体和复杂事件处理器的成本。
Flutter 策略
- 左右区域都使用
ListView.builder,只构建可见任务行。 - 时间表头和网格由
CustomPainter批量绘制。 - 依赖线按可见行与水平视口裁剪。
- 可关闭的行入场过渡只作用于当前新建的虚拟行。
onVisibleRangeChanged为远程窗口加载提供日期和行索引。
业务侧验收
- 先在默认渲染下记录
getRenderStats()、DOM 数量和滚动帧耗时。 - 再逐项启用自定义任务条、图片纹理、依赖线与业务事件,确认是哪一层增加成本。
- 在快速滚动、拖动、切换维度和页面后台化时检查持续动画是否暂停。
- 远程窗口请求按“日期范围 + 行范围”建立稳定键,取消离开视口的旧请求。
- 在目标设备而非开发机上复测;移动端应同时覆盖竖屏、横屏与系统减少动态效果。
