首页 / 资讯中心 / 文章详情

systematic-debugging - condition-based-waiting

systematic-debugging - condition-based-waiting ★ FEATURED ARTICLE
基于条件的等待概述不稳定的测试常常用任意的延迟来猜测时序。这会造成竞态条件测试在快速机器上通过但在负载下或在 CI 中失败。核心原则等待您真正关心的条件而不是猜测需要多长时间。何时使用digraph when_to_use { Test uses setTimeout/sleep? [shapediamond]; Testing timing behavior? [shapediamond]; Document WHY timeout needed [shapebox]; Use condition-based waiting [shapebox]; Test uses setTimeout/sleep? - Testing timing behavior? [labelyes]; Testing timing behavior? - Document WHY timeout needed [labelyes]; Testing timing behavior? - Use condition-based waiting [labelno]; }使用场景测试中有任意的延迟setTimeout、sleep、time.sleep()测试不稳定有时通过负载下失败并行运行时测试超时等待异步操作完成不要使用的场景测试实际的时序行为防抖、节流间隔使用任意超时时务必记录为什么需要核心模式// ❌ 之前猜测时序awaitnewPromise(rsetTimeout(r,50));constresultgetResult();expect(result).toBeDefined();// ✅ 之后等待条件awaitwaitFor(()getResult()!undefined);constresultgetResult();expect(result).toBeDefined();快速模式场景模式等待事件waitFor(() events.find(e e.type DONE))等待状态waitFor(() machine.state ready)等待数量waitFor(() items.length 5)等待文件waitFor(() fs.existsSync(path))复杂条件waitFor(() obj.ready obj.value 10)实现通用轮询函数asyncfunctionwaitForT(condition:()T|undefined|null|false,description:string,timeoutMs5000):PromiseT{conststartTimeDate.now();while(true){constresultcondition();if(result)returnresult;if(Date.now()-startTimetimeoutMs){thrownewError(Timeout waiting for${description}after${timeoutMs}ms);}awaitnewPromise(rsetTimeout(r,10));// 每 10ms 轮询一次}}有关带领域特定辅助函数waitForEvent、waitForEventCount、waitForEventMatch的完整实现请参阅本目录中的condition-based-waiting-example.ts它来自实际的调试会话。常见错误❌ 轮询过快setTimeout(check, 1)- 浪费 CPU✅ 修复每 10ms 轮询一次❌ 没有超时如果条件永远不满足会无限循环✅ 修复始终包含带清晰错误信息的超时❌ 陈旧数据在循环前缓存状态✅ 修复在循环内调用 getter 以获取新鲜数据任意超时何时是正确的// 工具每 100ms 触发一次 - 需要 2 次触发来验证部分输出awaitwaitForEvent(manager,TOOL_STARTED);// 首先等待条件awaitnewPromise(rsetTimeout(r,200));// 然后等待定时行为// 200ms 以 100ms 间隔触发 2 次 - 有记录且合理要求首先等待触发条件基于已知的时序不是猜测用注释解释为什么实际影响来自调试会话2025-10-03修复了 3 个文件中的 15 个不稳定测试通过率60% → 100%执行时间快 40%不再有竞态条件
阅读完成 · 觉得有帮助?
咨询建站