应使用 Jest 的 fake timers 替代真实 setTimeout 进行测试,通过 jest.useFakeTimers()、jest.advanceTimersByTime() 等方法实现可控、快速、可断言的定时器模拟,避免依赖真实时间流逝导致的慢速与不稳定。

在测试中无法真正“精确控制” setTimeout 的实际延迟,因为它的执行受事件循环、主线程阻塞、浏览器节流等 runtime 机制制约。但你可以**绕过真实定时器**,用可预测、可操控的方式模拟它,从而让测试稳定、快速、可断言。
用 Jest 的 fake timers 模拟时间推进
Jest 内置了可靠的 timer mocking 机制,能冻结时间、手动快进、验证定时器是否被调用及参数是否正确:
- 启用 fake timers:
jest.useFakeTimers(); - 触发所有已设定的 setTimeout 回调:
jest.runAllTimers(); - 只推进指定毫秒(更贴近真实行为):
jest.advanceTimersByTime(5000); - 验证是否调用了 setTimeout:
expect(setTimeout).toHaveBeenCalledTimes(1); - 检查回调函数和延迟值:
expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), 3000);
避免在测试中依赖真实时间流逝
真实 setTimeout 会让测试变慢、不稳定(比如 5 秒延迟要等 5 秒),还可能因页面失活、后台标签页被节流而失败:
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
- 禁止使用
await new Promise(r => setTimeout(r, 5000))类写法做等待 - 不调用
jest.useRealTimers(),除非你明确需要测节流行为(极少场景) - 若需验证“延迟后状态”,直接调用
jest.advanceTimersByTime(ms)+ 断言 DOM 或 state
对自定义延迟工具函数做隔离测试
如果你封装了类似 delay(ms) 的 Promise 工具函数(基于 setTimeout),测试时应聚焦逻辑而非时间精度:
- 用
jest.useFakeTimers()后调用delay(100) - 用
await jest.runAllTimers();或await jest.advanceTimersByTime(100); - 断言 Promise 是否 resolve,以及 resolve 值是否为
undefined(或你设计的返回值) - 不测试“是否刚好 100ms 后 resolve”,只测“是否在 timer 触发后 resolve”
注意跨环境差异:Node.js 与浏览器
Node.js 中 setTimeout 行为比浏览器更稳定,但仍受 event loop 影响;而浏览器中还有标签页可见性、最小延迟(4ms/1000ms)、系统休眠等干扰:
- Jest 默认运行在 Node.js 环境,fake timers 在此处最可靠
- 若用 Cypress / Playwright 做 E2E 测试,应改用
cy.clock()+cy.tick()控制时间 - 不要指望在真实浏览器自动化测试里获得毫秒级精准延迟 —— 那不是测试目标,而是运行约束

















