夜雨聆风学习资料网

ARTICLE · 1272006

AI36计:不是变量没清空,是AI检查时机太早

AI36计:不是变量没清空,是AI检查时机太早

系列第 08 篇 · 治理根因 7/8 一本几十章的书,每一章的正文里,都齐刷刷躺着同一段「版权信息」和「前言」。

现象:打开哪一章,前面都是版权

先看一个让我头皮发麻的场景。

AI要把一本书逐章抓成Markdown。结果抓完后抽查,发现一个诡异现象:打开第 5 章,正文前面躺着版权页;打开第 20 章,前面还是版权页;打开第 50 章,前面依然是版权页,还多了一段「前言」。

也就是说,每一章的正常正文之前,都被硬塞进了本该只出现一次的书本前置内容。这书没法读。

更诡异的是:命令行版本抓出来的同一本书,一点问题都没有。只有新做的桌面版本才会有这个「混入」。

第一反应,往往是错的

排查的第一反应特别顺理成章:「变量没清空」。

抓取原理是 hook 住 canvas 的绘制,把每一笔fillText的文字攒下来。抓完一章,就该把缓存清空,否则上一章的字会漏到下一章。

所以看到「上一章的内容混进这一章」,任谁的第一判断都是:有个缓存数组忘了clear。

AI去查,果然——桌面版为了做「单章跳转」,新增了page.goto直接跳到目标章。而page.goto会触发浏览器重新执行注入脚本,于是AI顺着这条线,怀疑是「注入脚本重跑,把缓存弄丢了又没重建」。

两个假设都听起来很对。但改完之后,混入纹丝不动。

真相:不是「没清空」,是「清空之前根本没收集全」

真正的问题,藏在一个AI想当然的地方——检查时机的假设。

代码里有一个变量,记的是「导航那一刻,已经捕获了多少文字」(capturedBeforeNav)。逻辑是:翻到新章节时,先记下当前位置,这样新收集的文字如果和旧内容重叠,就能用这个偏移量把它跳过去。

问题就出在这句「导航那一刻,已经捕获了多少」。

AI假设:等到page.goto跳转完成时,旧章节的 canvas 已经渲染完了,capturedBeforeNav记下的是一个「完整」的数字。

但实际上,canvas 的渲染是异步的。page.goto返回了、页面「看起来」跳过去了,canvas 还在后台一笔一笔地画。AI只等了 6 秒就去记capturedBeforeNav,结果记到一个偏小的数(比如2)。

于是灾难发生了:

1.旧章节的 canvas 还没画完,AI记下capturedBeforeNav = 2;

2.接着旧章节剩下的字才慢慢画出来——这些字被当成了「新章节」的字收集进来;

3.因为偏移量是2(而不是真正的几千),跳过逻辑形同虚设;

4.最后,版权页、前言这些「迟到」的旧字,就齐刷刷地混进了新章节的开头。

「变量没清空」是表象,「检查时机太早、导致偏移量记错」才是根因。

修复也简单得反直觉:别急着检查,等 canvas 渲染稳定了,再记capturedBeforeNav。记下完整数字,偏移量才能真正跳过旧内容。

为什么修了 10 个提交还是没修好

找到根因后,AI以为问题解决了。结果修它用了 10 个提交,而且还差点没修住。

因为它牵引出了一连串「打地鼠」:

·修好了「混入」→正文的分段就错了(段落全黏在一起);

·修好了分段 → 这一章的图片又丢了;

·修好了图片 → 结尾开始冒出s='content'>这样的HTML 碎片;

·修好了碎片 → 又冒出一个「变量重复声明」的 SyntaxError……

每修一个,另一个地方就开出新口子。十个提交排下来,代码被AI改得越来越不像自己。

一句很戳的话:「你不是在修bug,你是在用新的 bug 覆盖旧的 bug。」

止损:把 10 个提交全部扔了

第十个提交之后,AI看了一眼diff,决定停手。

我没有继续「再改一次」,而是做了一件当时觉得丢脸、事后觉得最聪明的事:让AI把这 10 个提交全部撤销,回退到那个没有「混入」问题的命令行基线版本。

回退的时候我留了一个心眼:基线里那个「API 版本号升级」是好的、应该保留的,那就只回退抓取核心的 6 个文件,保留这一个正确的改动。

结果证明:回退之后,问题虽然没「根治」,但项目立刻回到了一个可用的、稳定的状态。而那个「根治」,可以等冷静下来、带着基线和清单,再慢慢做。

可复用经验

1.表面现象和真实原因是两回事。「上一章内容混入」听起来百分百是「没清空」,但真相是「时机太早导致偏移量记错」。第一反应是经验,也是陷阱。

2.异步渲染,别用「固定等几秒」去赌。page.goto返回 ≠ canvas 画完。要么等稳定的信号,要么用明确的渲染完成条件。

3.「修一个开一个」是失控的信号。当你发现自己在打地鼠时,停手,而不是继续——继续只会把代码改得更不可识别。

4.回退基线是止损,不是认输。越改越乱时,先退回一个可用的状态,再带着基线和清单慢慢根治,远好过硬撑。

下一篇,我们聊聊另一类看不见的坑:一个 exe 为什么静默崩溃,而且不是代码的错。

下一篇预告:《exe 静默崩溃:不是代码的错,是打包环境的错》

相关学习资料