javascript假定时器通过替换settimeout等api实现时间快进,jest用jest.usefaketimers()启用,jest.advancetimersbytime()推进时间,需jest.userealtimers()恢复;注意其仅控制宏任务,promise微任务需配合await或waitfor验证。

JavaScript 中使用假定时器(Fake Timers)测试含延时任务的代码,核心是用测试框架提供的工具(如 Jest 或 Sinon)替换原生 setTimeout、setInterval 等全局定时器函数,让时间“快进”而非真实等待,从而快速验证异步逻辑是否按预期执行。
Jest 中启用和控制假定时器
Jest 内置了 jest.useFakeTimers() 和配套的推进方法,是最常用的方式:
- 在测试前调用
jest.useFakeTimers(),它会劫持所有定时器 API(setTimeout、setInterval、clearTimeout等) - 触发被测代码后,用
jest.runAllTimers()立即执行所有已注册但未触发的定时器 - 若需模拟“经过 100ms”,可用
jest.advanceTimersByTime(100) - 测试结束后建议调用
jest.useRealTimers()恢复原生行为,避免影响其他测试
示例:测试一个 500ms 后更新状态的函数
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
test('should update status after 500ms', () => {
jest.useFakeTimers();
const mockCallback = jest.fn();
myDelayedFunction(mockCallback); // 内部调用了 setTimeout(..., 500)
expect(mockCallback).not.toHaveBeenCalled();
jest.advanceTimersByTime(500);
expect(mockCallback).toHaveBeenCalledTimes(1);
jest.useRealTimers();
});
处理嵌套定时器与清理逻辑
假定时器默认不自动清理已清除的定时器(比如被 clearTimeout 取消的),但 Jest 会正确识别并跳过它们:
- 如果代码中根据条件调用
clearTimeout(id),假定时器仍能准确反映该定时器不会执行 - 使用
jest.runOnlyPendingTimers()只执行当前队列中最先的一个定时器,适合测试循环或链式调用 - 用
jest.getTimerCount()可断言剩余未执行的定时器数量,辅助验证清理是否到位
注意异步边界与 Promise 微任务
假定时器只控制宏任务(macrotask)如 setTimeout,不影响 Promise.then、queueMicrotask 等微任务:
- 若被测代码在
setTimeout回调中返回 Promise,需配合await waitFor或async/await验证后续状态 - 不要期望
jest.advanceTimersByTime()自动等待 Promise 完成;需显式await或用waitFor包裹断言 - 例如:定时器触发后发起 fetch → 返回 Promise → 更新 state,此时应
await waitFor(() => expect(...).toBe(...))
替代方案:Sinon.js 的 fake timers
在非 Jest 环境(如 Mocha + Chai)中,可用 Sinon 提供的 sinon.useFakeTimers():
- 返回一个 timer 对象,支持
.tick(ms)(类似advanceTimersByTime)、.runAll()等方法 - 必须手动调用
.restore()恢复原生定时器,否则会影响后续测试 - 对
Date.now也提供模拟支持(通过now选项),适合依赖当前时间的逻辑
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










