v0.65.1–0.65.2:任务详情页性能大幅优化
最近两个补丁版本专注于一件事:让任务详情页加载和响应更快。以下是改动内容和原因。
5秒导航卡顿
影响最大的修复是看板导航的性能回退——从看板点击任务后,UI会冻结长达5秒。
根本原因很微妙。之前的一个优化提前预加载了 TaskDetail 代码块,让 React.lazy() 立即解析。听起来应该更快,但实际效果相反:没有了短暂的 Suspense 暂停,React 会同步提交路由变更。这意味着要在一帧内卸载整个看板——数百个可排序的项目、拖拽上下文——然后新页面才能开始挂载。
使用标准的懒加载,首次导航会触发短暂的 Suspense 边界。React Router 使用 transition 保持旧页面可见,清理在后台非阻塞地进行。后续导航直接使用缓存的代码块。
修复方案:恢复标准的 React.lazy(),让框架做它该做的事。
后端:修复任务详情的 N+1 查询
GET /todolist/:id 接口有两个问题:
-
重复查询 ——
enrichItem()调用loadRelatedData()获取笔记和分享链接,但GetByIDEnriched()已经加载了这些关联数据。每个请求多跑了2个冗余查询。 -
关联任务的 N+1 —— 每个关联任务都在循环中单独获取。一个有5个关联任务的任务意味着5条独立的
SELECT语句。
修复后,任务详情请求总共只需4次查询(主记录 + 笔记 + 分享链接 + 一次批量 WHERE id IN (...) 获取关联任务),之前至少需要7次以上。
使用 IntersectionObserver 延迟加载笔记编辑器
UnDercontrol 中的任务可以有很多笔记,每个笔记都使用 TipTap 富文本编辑器渲染。每个 TipTap 实例都会创建 DOM 节点、事件监听器和扩展链——一次性初始化10个编辑器的开销很可观。
现在只有前2个笔记立即渲染编辑器。其余的显示轻量级占位符,直到滚动到距视口200px以内才加载。对于有10个笔记的任务,这避免了预先初始化8个编辑器实例。
切换编辑模式不再闪烁
将笔记从阅读模式切换到编辑模式时,之前会出现短暂的白色闪烁。原因有二:
- TipTap 默认行为会等一帧再渲染内容
- 资源 URL(
resource://...)在设置任何内容之前就开始解析,所以编辑器在异步解析完成前是空的
修复方案:在编辑器上设置 immediatelyRender: true,先同步加载原始 markdown 内容。资源图片在后台解析——你立刻看到文字,图片稍后填充。如果内容中完全没有 resource:// URL,则直接跳过处理步骤。
编辑器工具栏修复
几个较小但恼人的编辑器问题也得到了解决:
- 水平滚动时工具栏冻结 —— 格式化工具栏使用
fixed定位,向右滚动时停留在 x=0。改为sticky定位,随容器滚动。 - 切换按钮滚出视野 —— 长笔记中,编辑/预览切换按钮会滚出可见区域。现在固定在 sticky 操作栏中。
- 移动端操作栏被遮挡 —— 移动端编辑器操作栏被浮动聊天按钮遮住。调高位置以避开遮挡。
中国大陆下载镜像
对于中国大陆用户,从默认CDN(Cloudflare R2)下载桌面应用可能很慢或不稳定。我们在下载对话框中添加了「中国大陆下载」按钮,从 Bitiful(国内CDN)拉取安装包。下载指标会追踪使用了哪个镜像,方便我们监控使用情况。
发布流程现在会自动将构建产物上传到 R2 和 Bitiful 两个渠道,并清理 Bitiful 上的旧版本(保留最新2个)以管理存储空间。
这些改动已在 v0.65.2 中发布。如果你是自部署用户,拉取最新镜像即可。