跳转至

重复原生链接导致 PDF 首屏与交互停顿

2026-10-29。此前的 512px 瓦片优化只验证了 PDF 字节的出图路径;没有加载实际 Vault 的批注 sidecar,未覆盖这里的根因。

复现与原因

完整桌面应用打开 AgentCompass(papers/2607.13705),首屏长时间空白,框选和其他交互也可能等在大量后台任务之后。测试使用原 Vault 的本地副本,PDF、批注、版面与笔记均保留,SQLite 用只读连接备份;未改动原 Vault。

这份样本的 marks/annotations.json 为 17,757,601 bytes,共 19,808 条:

  • 19,800 条 LINK,除顶层 id 外,实际仅有 198 种内容,每种恰好重复 100 次。
  • 8 条用户 HIGHLIGHT。
  • PDFium 直接读取原 PDF,得到 198 条原生 LINK;它们的完整内容与这 19,800 条 LINK 匹配。

PDFium 为没有 /NM 的原生链接生成临时 UUID;当前引擎把它写入内存中的 PDF。应用导出全部批注到 sidecar,重开原始 PDF 后原生链接又获得新 id。旧实现仅按 id 去重,随后把 sidecar 逐项交给 importAnnotations。上游每项 dispatch 创建状态,最后 auto-commit 又为每项提交 createPageAnnotation。重复项因此增加了主线程状态复制、排序、DOM 链接命中层和引擎排队。已证实本样本存在这种重复;没有把当前 100 份的历史来源当成已追溯完成。

修复边界

annotation-items.ts 统一处理读取、保存、首次导入和文件监听重导入的判重:

  1. 保留原有 id 判重。
  2. 仅对没有 transfer context 的 LINK,忽略顶层瞬态 id,按其余完整内容生成稳定键。嵌套目标 id、页码、位置、颜色、flags、备注、日期、custom 等仍参与比较,JSON 属性顺序不影响结果。
  3. 导入时同时比较当前引擎已加载的批注,跳过已有原生链接。
  4. 不按内容合并普通高亮;带 transfer context 的记录保留,避免把二进制上下文当成空 JSON 后误合并。

读取旧文件只在内存中压缩,不在打开时自动重写。后续正常保存使用同一规则,避免链接副本继续增长。源 PDF 不重写。

实测

macOS 26.6.2 / WebKit,React 19.2.7、EmbedPDF 2.14.4,完整 Tauri 开发应用,真实 PDF + NOTES 分屏,uiScale=1、缩放适应宽度约 89.2%、DPR=2、本机 CJK 字体 fallback。基线为 0aa309003,修复条件只加入本次批注判重;512px 瓦片保持一致。

通过临时诊断记录引擎任务 call / enqueue / start / done 和页面图片 load、rAF 长帧;临时采集代码不提交。计时从 openDocumentBuffer 发起开始,图片 load 包括其加载与解码,不等同于 GPU 实际呈现时刻。以下为一次完整原生对照,不能当作所有 PDF 的固定耗时:

指标 修复前 仅批注判重后
首张 PDF 图片 load 48,048ms 526ms
首次 sidecar 创建任务 19,808 8
主线程长帧 观察到 41,661ms 首屏阶段最大约 156ms
第 3 页框选裁剪 大量任务队列持续数分钟,未取得可比裁剪值 PNG 裁剪 Task 176ms

修复后通过原生鼠标框选第 3 页插图,出现「批注备注」编辑器;原有高亮、页边备注与原生链接仍显示。框选耗时是裁剪任务值,不包含用户拖动时间和编辑器持久化完成时间,没有虚构修复前裁剪速度比。

只读 Node 调用同一判重函数,将真实 19,808 条压成 206 条约需 99ms,8 条高亮逐条保留。再与 198 条原生链接比较,实际只需导入 8 条高亮。

Chromium 实际阅读器加载同一批注 sidecar 后,经原生键盘事件编辑备注并提交,保存为 206 条(198 LINK + 8 HIGHLIGHT);卸载并重开阅读器后,8 条高亮与新备注仍保留。浏览器使用批注存储的既有内存 fallback,这部分不冒充 Host 文件写入验收。

回归测试覆盖属性顺序、重复 id、不同链接目标/位置/样式/备注/custom、二进制 transfer context、重叠用户高亮,以及连续导出重开后条目数不再增长。

补充验收与后续

解锁后的完整原生流程已补齐:实际编辑高亮备注、框选第 3 页、输入中文备注,Host 保存了高亮 sidecar、visual JSON 与裁剪 PNG。退出并重开后两类备注及裁剪图恢复,保存后的 sidecar 仍为 198 LINK + 8 HIGHLIGHT。逐项核对 8 条高亮的 id、几何、custom、颜色与原件一致,其余 7 条备注原文保留;原 PDF 和原批注文件哈希未变。调度的三轮原生对照另见可见页面优先性能对照。

已检查开发文档,仓库无独立 Roadmap / TODO。本问题已使用完整 Vault 副本验收首次打开、框选、批注保存与重开、链接跳转和连续切页;后续回归也应保留这一完整输入,只加载 PDF 字节会漏掉 sidecar 引起的性能问题。合法的大量不同批注仍可能触及上游逐项导入的成本,不能通过内容去重解决;如再复现,应单独测量批量导入调度,不能删除不同内容的批注来换取速度。