用搜索竞态测试 AI 写码能力
文章通过搜索请求乱序返回的最小案例,展示界面看似正常却可能呈现过期结果的问题。它用手动控制 Promise 完成顺序构造可复现测试,并明确未实际比较 Claude 与 ChatGPT。
AI 深度解读
搜索框看起来正常、能返回结果,不代表 AI 写对了代码。用户连续输入两次,只要响应顺序反过来,页面就可能把旧查询的结果显示在新查询下面,而且所有请求都成功了。
作者用这个小故障提出了一套更可检查的 AI 编程评估方法:先复现错误,再明确正确规则,最后检查修复和测试是否一致。文章没有实际对比 Claude 与 ChatGPT,也不排名;它提供的是一种比成功演示更有辨别力的考法。
请求都成功了,搜索结果为什么还是错的
原始实现很简单:search(query, request) 等待 request(query) 返回,再把结果赋给 visibleResults。单独执行一次,几乎看不出问题。
但用户先输入 re,接着输入 react,两次搜索就会同时在途。如果 react 的响应先到,页面先显示正确结果;随后 re 的响应到达,又把它覆盖。此时输入框仍是 react,结果列表却属于 re。
这是异步请求的竞态:完成顺序决定了最终界面,而完成顺序未必等于用户操作顺序。
为了稳定复现,作者没有依赖网络速度或定时器,而是用下面的测试夹具手动控制两个 Promise 的完成顺序。这里的 search 指上述原始实现:
const pending = new Map();
const request = query => new Promise(resolve => {
pending.set(query, resolve);
});
const first = search('re', request);
const second = search('react', request);
pending.get('react')(['React result']);
await second;
pending.get('re')(['Older result']);
await first;
console.log(visibleResults); // ['Older result']
关键是两次 pending.get(...) 的调用顺序:先让新请求完成,再让旧请求完成。Map 保存每个请求的 resolve,测试因此可以主动制造故障,不必碰运气。
基于定时器的测试可能恰好让响应按正常顺序返回,把这个错误藏起来。
修复之前,先写清谁有权更新界面
作者给出的规则是:只有最新发起的搜索,才能替换当前可见结果。
正确性取决于哪次搜索最新,而不是哪个响应最后到达。
下面的实现用递增序号落实这条规则:
let latestSearch = 0;
let visibleResults = [];
async function search(query, request) {
const sequence = ++latestSearch;
const results = await request(query);
if (sequence !== latestSearch) return;
visibleResults = results;
}
要看的是 if (sequence !== latestSearch) return;:每次调用保存自己的序号,等待结束后再检查它是否仍然最新。旧请求可以完成,但不能继续写入界面状态。
作者表示,使用同一套受控顺序测试,原实现最终得到 ['Older result'],修复后保留 ['React result'],两种结果都通过可执行断言检查过。不过,正文没有展示断言代码。
这个例子刻意省略了渲染、加载状态、错误展示、取消请求和组件清理。尤其需要单独决定:最新搜索失败时,界面应该显示什么?此前成功返回的结果,不会自动成为新查询的正确答案。
文章也提到 Promise 的完成机制,以及用于中止受支持请求的 AbortController。取消过期请求有用,但仍要明确哪些请求有权更新界面。
我的判断
这套方法适合作为 AI 编程工具的一个小型评估题,因为它把验收对象从截图扩展到了行为:工具能否解释故障,补丁能否落实规则,测试能否击中原来的错误。
作者建议给每个工具相同的函数和测试夹具,要求先解释、再做有限修复,并补一个能让原实现失败的检查。保留补丁、解释和测试结果,再核对三者是否一致。随后增加第三次搜索,或者让最新请求失败,观察它是否仍能讲清状态变化。
但它不能直接选出最适合团队的模型。作者没有运行 Claude 与 ChatGPT 的对照,也没有提供模型版本、评测成绩或团队效率数据。它更像一个有可执行验证支撑的评估建议,而不是模型优劣的实测结论。
和只验收成功路径相比,这个题更容易暴露异步逻辑漏洞;和完整代码库任务相比,它覆盖得很窄。序号方案也只保护了示例里的结果赋值,不能据此认定加载状态、错误状态和组件生命周期都已处理妥当。
能拿来做什么
- 评估 AI 编程工具时,可以给它相同的搜索函数和乱序测试,要求先解释错误,再提交有限补丁,并提供能让原实现失败的检查。
- 检查前端搜索交互时,可以把「只有最新搜索能更新结果」写成验收规则,再用可手动完成的 Promise 验证旧响应不会覆盖新结果。
- 接受修复前,可以追加「第三次搜索提前发起」和「最新请求失败」两种条件,同时明确失败后的展示策略,避免只修好一条成功路径。