复杂工程的实践测试
Test1
git : http://deve.work:33333/colin/mde.git
commit : c61827061d6a34cbd2ca2fae62b59fcb780f192e
prompt : 在vscode里面打开一个markdown非常慢,每次打开一个文件都要白屏很久
fix commit : 3e64dfab0643fecc583bb1e77467373d7e43854e
答案:
-
Lute 双重加载 (3.8MB)
- 之前的代码在
<script>的 onload 回调里才设 id="vditorLuteScript"。如果 Vditor 的 addScript() 在 lute 还没加载完时就运行了,它找不到这个 id,就会再创建一个 script 标签重新请求 3.8MB。 - 修复:用 window.__luteReady promise 跟踪 lute 加载状态,_boot() 等 lute 加载完毕(id 已设好)后再初始化 Vditor,避免双重加载。
- 之前的代码在
-
Icons 同步 XHR (43KB)
<script defer>加载了 ant.js,但没有 id="vditorIconScript"。Vditor 初始化后调用 addScriptSync() 时找不到这个 id,就用同步 XHR 重新请求一遍——这会阻塞主线程。- 修复:给 defer 的 script 标签加上 id="vditorIconScript",addScriptSync 检查到已存在就直接跳过。
-
Loading 遮罩 1200ms 人工延迟
- 之前 Vditor ready 之后还要等 1200ms 才移除 loading 遮罩。
- 修复:ready 后立即移除。
结果:
- Opus4.7 经过非常多轮的尝试才修复,消耗大概500K的上下文
Test2
git : http://deve.work:33333/colin/mde.git
commit : 5b9134576b7a11b52dc1c7962d2827c487c698bc
prompt : 在 inline code 的元素的 内部开头和外部结尾 不显示光标。虽然可以在 进行输入。inling code 边界部分,应该能有两个光标,分别在 inling code内部和外部。但是现在是 内部开头和外部结尾 不显示光标。
fix commit : b234863461bed88652e6d6169f81ece3696416b6
答案:
根因找到了三个叠加的问题:
1. <code> 的行高和 marker 的行高不同(13.6 vs 16px),光标画到不同 y
2. marker 默认 overflow: hidden + width: 0,把光标 glyph 本身裁掉了
3. 要隐藏反引号文字就得 color: transparent,但 caret-color: auto 会跟着 color 也变透明
修复:对 inline-code 的 marker 加了 height: 1em; font-size: 85%; overflow: visible; color: transparent; caret-color: var(--textarea-text-color)。之前我反复用 headless chrome 和 getBoundingClientRect 判断"光标位置对了",但那只算逻辑位置;实际绘制要用新 headless 模式(headless: 'new')才会画 caret,发现 overflow 裁掉的问题。请重新跑 ./run-local-vditor-demo.sh 或在 VS Code 里 Reload Window 验证。
结果:
- Opus4.7 经过非常多轮的尝试才修复,消耗大概1M的上下文
Test3
git: http://deve.work:33333/colin/logix
commit: 49f4742415cdd6ca2067e8edef9b021b0f810d33
prompt:
src/utils/insight 这个目录里面是一个信号的查看程序。现在有如下问题
1. 一个信号全是 同一个数值,在缩小的时候,会被显示成多个分离的色块
2. 不一样的数值,在特定的缩放情况下,为什么会显示成一个整块的色块,还标示了不正确的数值
3. 全部是一样的值 在不同的尺度下,会显示出 不同颜色的色块
Fable5-xhigh: 来来回回修复了10版本才修复好,最后是开发了一个哨兵,在网页端显示有问题的时候会生成一个json,2次之后就定位到了问题。
答案:
报告揭示了什么
把报告里的完整像素行与服务端数据(连续 30 次查询完全一致,数据无变化)对照后:
- 七条不同的 lane 在某一时刻渲染出逐像素相同的内容——war_pipe、wait_pipe、vec1d 四条、mac2d.inflight 全部显示着同一条 lane
的画面(一次全是 stall 的纯绿,一次全是 mac2d.state 的绿红相间);
- wait_reg 行里出现 #377f1a 和 #bdb1a8——分别是绿 #1a7f37、灰 #a8b1bd 的红蓝通道互换,整个代码里不存在产生这两个颜色的路径。
「别的 lane 的内容」+「通道互换」指向同一处:渲染时所有 lane 共用一块暂存 canvas,每条 lane 先 putImageData 写入、紧接着
drawImage 取出,一帧内重复十三次。在 GPU 加速的 canvas上(你的环境),这种「写后立读、高频复用同一源」会踩到纹理同步竞态——取到上一条 lane 的旧纹理(lane 内容互串)或按 BGRA
误读(红蓝互换)。
这一个根因同时解释了之前所有解释不了的事:为什么只显示单个信号就没问题(一帧只写读一次,无复用);为什么我九轮无法复现(我的无头
浏览器走软件渲染,没有 GPU 纹理路径);为什么时好时坏、与缩放路径无关(取决于 GPU 调度时机)。
修复(v7.21)
废除暂存 canvas 和 drawImage:lane 图像在内存里按行复制成全高 ImageData,一次 putImageData 直接写入目标 canvas——纯 CPU
像素写入,不经过任何纹理采样,竞态在结构上不存在了。同时修了哨兵的两处误报(页面初载「无数据→有数据」不再算不一致;同一视野同一
lane 只报一次)。
回归验证:6 条长保持段 × 5 个缩放档颜色与调色板逐字节相等;连续滚轮手势哨兵 0 报告;整页截图正常;无 JS 错误。
确认根因就是那个 GPU canvas 竞态。十轮排查,最终是「共享暂存 canvas
的写后立读」这个从第一版就存在的问题——它只在硬件加速渲染下偶发,所以你那里始终能看到、我这里始终复现不了。
最终留在工作区的改动(你的 stage 我始终没动,提交时机和方式由你定):
┌─────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 文件 │ 内容 │
├─────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ web/app │ 直接 putImageData 渲染(决定性修复);采样上色语义(颜色只能是真实值的颜色);选区只描边不重新上色;字体加载后清 │
│ .js │ 空测量缓存;页面自动跟随代码更新;渲染一致性哨兵(右上角红色计数 + B 键导出);版本不匹配横幅 │
├─────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ server. │ 「runs │
│ py │ 超预算但金字塔网格比像素粗」的缩放带按像素粒度动态量化;预热期间请求路径不做秒级解码;数据接口校验前端版本 │
├─────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ reader. │ 多遍重叠记录的 trace(gmp 那类多 case 测试)按时间跨度最长的一遍展示 │
│ py │ │
├─────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ indexer │ 索引格式 v7(配合 pass 选取),旧索引自动重建 │
│ .py │ │
└─────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
两个可选项,按你喜好处理:
- 哨兵和自动跟新可以保留(开销极小:视图静止 350ms 后才做一次指纹、4 秒一次 HEAD
请求),以后再遇到渲染问题它会当场取证;觉得多余我也可以拆掉。
- src/utils/insight/ 下还留着排查用的截图和哨兵
JSON(1.png、2.png、time*.png、insight_sentinel_*.json),是未跟踪文件,不用了可以删。
修复commit: 20a88b48fde3fdf1bcc09659f65df6da5deb3de3