跳到内容

性能指南

本页记录 Mindwtr(桌面端、移动端和核心包)的实用性能模式。

影响最大的区域

  • 大型列表的筛选与排序
  • 项目/任务顺序更新
  • 同步合并与附件协调
  • 过宽的 store 订阅引起的重复渲染
  • SQLite 查询模式(搜索、日期筛选、项目/状态视图)

UI 渲染指南

  1. 优先使用范围较窄的 store selector,避免选择整个 store 对象。
  2. 将相关 selector 分组,并缓存派生集合。
  3. 保持条目组件纯净;把昂贵的转换提升到列表级缓存中。
  4. 大型列表使用虚拟化,并避免在高频路径中动态重新计算高度。
  5. 避免在大型映射列表中创建新的行内回调/对象。

当前桌面端列表行依赖已缓存的 TaskItem 渲染,因此更改列表、项目、日程、日历或回顾视图时,应保持任务行 props 稳定。如果视图需要额外的逐行元数据,请在列表级一次性派生,而不是在每一行的渲染过程中构建新对象。

渲染优化手册

界面感觉缓慢时,请按以下顺序处理:

  1. 先验证列表项目的渲染次数(React DevTools profiler)。
  2. 将静态常量/样式提升到渲染函数之外。
  3. 使用带缓存的较重子组件(React.memo),必要时明确比较 props 是否相等。
  4. 按职责拆分大型组件(标题/表单/列表/模态框),使状态更新保持局部。
  5. 用较小的已缓存 selector/辅助函数替代过宽的依赖数组。

桌面端项目列表虚拟化

  • 对共享主工作区滚动容器的大型桌面任务列表使用 @tanstack/react-virtual
  • 行 key 应基于任务 ID;对于可以编辑、选择、移动或重排的任务行,绝不要使用索引。
  • 任务卡高度可能变化时,请测量虚拟行,并使用保守的行高度估值,以免滚动跳跃。
  • 通过虚拟化现有的可排序行组件来保留拖放/重排语义,而不是换用独立的行 UI。
  • 避免项目分区内出现嵌套滚动容器。如果虚拟列表位于项目元数据或分区标题下方,请用 scroll margin 考虑列表偏移。
  • 为大型列表回归添加有上限的渲染次数测试。测试应证明挂载的行数接近可见窗口加 overscan,而不是完整任务数。

FlatList / 虚拟化调优(移动端)

  • 按界面有意识地设置 initialNumToRendermaxToRenderPerBatchwindowSize
  • 在可行时提供 getItemLayout(固定值或测量回退值)。
  • 对较大的列表启用 removeClippedSubviews
  • 保持 keyExtractor 稳定,并避免使用索引 key。
  • 避免在深层嵌套的项目树中使用行内匿名 renderer。

普通任务界面应继续使用 FlatList。对于嵌入现有 ScrollView 的任务列表,请使用带占位行的手动可见窗口切片,而不是嵌套另一条纵向虚拟列表,这样滑动、下拉、键盘和拖放手势可以共用一个滚动所有者。 日历特定规则:虚拟化无界结果集,而不是固定的日历脚手架。移动端日程视图会随每个可见任务/事件而增长,应继续使用 FlatList;日视图和周视图时间线受可见小时网格限制,月视图单元格受日历周数限制,因此可以使用 ScrollView,但任务/事件行必须在渲染循环之外预先筛选。

同步性能指南

  1. 合并前验证载荷结构,以便快速失败。
  2. 合并应确定且相对实体数量保持 O(n)(按 ID 建立 map,避免嵌套扫描)。
  3. 先协调附件元数据;将文件 IO/网络操作推迟到独立的同步阶段。
  4. 重试应带退避和次数上限,并区分可重试错误与终止错误。
  5. 在一个同步周期内缓存后端配置读取,以减少重复的存储访问。

合并期间,同步引擎维护索引化的冲突/修订查找。新增同步实体类型或冲突报告时,应保留这种索引结构,而不是重新引入逐实体扫描完整集合。

同步调优技巧

  1. 移动网络上的附件上传/下载并发数应保持保守。
  2. 分别调整元数据与附件的超时和重试窗口。
  3. 切换到离线状态时应迅速中止;失去连接后避免较长的重试链。
  4. 对长时间运行的附件阶段使用进度检测。
  5. 跟踪每次同步运行的冲突数量、最大时钟偏差和时间戳调整。
  6. 将同步冲突样本视为有上限的诊断信息。保持较小的样本数量和 diff key 上限,以免冲突报告主导大型合并。

同步调试清单

如果同步延迟出现回归:

  1. 分别比较本地读取、合并、远程写入和附件阶段。
  2. 验证限流响应(429)是否引发级联重试。
  3. 检查附件哈希验证/重试是否反复失败。
  4. 确认远程载荷大小和集合数量在配置的限制内。
  5. 捕获缓慢时段附近带有时间戳和请求 ID 的日志样本。

发布模式关键旅程分析

在进行大范围性能更改前,请分析真实的 release/profile 构建。开发构建和测试运行器适合用于防护,但可能掩盖真正的主导层:数据派生、React 渲染/提交、虚拟化、持久化或原生/UI 线程工作。

关键旅程预算

将以下指标用作排查预算,而不是硬性产品保证。尽可能记录 p50 和 p95,并在每个结果旁附上数据结构。

旅程Android release 预算桌面端 release 预算主要信号
快速记录打开并接受第一次按键打开 <= 500 ms,输入延迟 <= 100 ms打开 <= 300 ms,输入延迟 <= 100 ms从命令/点击到可编辑输入框及接受第一个字符的时间
任务完成/切换视觉响应 <= 150 ms,保存排队 <= 500 ms视觉响应 <= 100 ms,保存排队 <= 300 ms输入到视觉更新的时间及持久化阶段
任务编辑的打开/保存/关闭打开 <= 300 ms,保存/关闭 <= 300 ms打开 <= 200 ms,保存/关闭 <= 200 ms模态框/底部面板的提交时间和保存刷新时间
打开包含 100+ 个任务的项目<= 2,000 ms<= 1,000 ms从导航到可交互任务列表的时间
在专注/收集箱/项目已挂载时打开/关闭选择器<= 200 ms<= 150 ms选择器过渡和父视图重新计算
专注、收集箱和项目视图切换<= 500 ms<= 300 ms从路由/视图切换到可交互状态的时间
即输即搜每次按键 p95 <= 150 ms每次按键 p95 <= 100 ms从按键到可见结果更新的时间

捕获矩阵

将捕获结果附在议题或后续议题中。每项捕获结果都应注明 commit、应用版本、安装渠道、设备、OS、数据结构、旅程和 artifact 链接。

平台所需构建工具捕获 artifact要记录的主导层
Android带有代表性本地数据的 Release 或 profile APK/AABAndroid Studio profiler、Hermes sampling,或可用时使用 FlipperCPU trace 或 Hermes profile,以及屏幕录制/时间戳JavaScript 派生、React 渲染/提交、列表虚拟化、SQLite/持久化、原生/UI 线程
桌面端带有代表性本地数据的 Tauri release 构建WebView DevTools Performance profiler 和应用诊断日志Performance trace 以及诊断时间戳数据派生、React 渲染/提交、Web 虚拟化、SQLite/持久化、WebView/原生 shell

捕获说明模板

markdown
Commit:
Version/channel:
Platform/device/OS:
Dataset:
- tasks:
- projects:
- largest project task count:
- contexts/tags:
Journey:
Tool/artifact:
Observed p50/p95:
Dominant layer:
Notes:
Follow-up issue:

层级分类

  • 数据派生:profile 显示在渲染开始前,反复进行完整 store 扫描、排序/筛选、数量聚合或 selector 抖动。优先使用查询范围内的 selector 和派生索引。在 #647 中跟踪。
  • React 渲染/提交:profile 显示提交时间较长、行反复渲染、props 不稳定或订阅过宽。在更改数据模型前,先缓存行并缩小订阅范围。
  • 虚拟化:profile 显示为一个可见列表挂载了数千个行组件。使用平台虚拟化工具和有上限的渲染次数测试。在 #648 中跟踪。
  • 持久化:UI 卡顿与保存刷新、SQLite 工作、导入/导出、同步写入或 JSON 序列化同时发生。将紧急的视觉更新与存储工作分开。
  • 原生/UI 线程:Android trace 或桌面端 WebView trace 显示动画/布局/输入卡顿发生在 JavaScript 之外。减少布局抖动、嵌套滚动或原生桥接通信。

对于 #643 中报告的项目打开缓慢问题,请先捕获 Android 和桌面端数据。如果数据派生占主导,请使用 #647。如果挂载行数占主导,请使用 #648。如果持久化或原生/UI 线程卡顿占主导,请创建一个范围更小的后续议题,并附上捕获 artifact 和确切旅程。

数据库指南

  1. 在可用时使用 FTS 索引进行全文搜索。
  2. 为常见状态/项目/日期筛选建立索引。
  3. 大型导入/同步保存路径应在事务中批量写入。
  4. 在读取边界规范化 JSON 列,并避免反复解析/序列化循环。

性能分析清单

  1. 使用真实的数据集(数千个任务、大型项目)复现。
  2. 测量更改前后(渲染次数、查询时间、同步时长)。
  3. 检查长时间会话期间的内存增长。
  4. 验证低端设备/模拟器上没有回归。

性能预算建议

  • 列表交互应保持响应迅速(可行时采用 <16ms 的帧预算)。
  • 典型本地数据集上的搜索请求应低于 100ms。
  • 同步合并应随实体数量线性扩展。
  • 避免用文件/网络操作阻塞 UI 线程。

持续性能维护

  1. 修复回归时添加有针对性的测试(渲染抖动、合并复杂度、重试行为)。
  2. 在 CI 中保留关键视图和同步路径的预算检查。
  3. 优先进行小而可测的改进,而不是大范围的推测性重构。
  4. 每次优化后重新分析,以验证实际效果。

相关文档

Mindwtr 免费、开源且本地优先。
Getting Things Done 和 GTD 是 David Allen Company 的注册商标。Mindwtr 与 David Allen Company 不存在关联,亦未获得其认可或赞助。