You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Sinon fake timers实现时间跳转?(模拟切tab后返回场景)

如何用Sinon fake-timers模拟浏览器切tab后恢复的时间跳转场景?

要模拟浏览器切tab后时间大幅跳转但期间不执行requestAnimationFrame(RAF)回调的场景,核心是只推进模拟时间,不触发RAF队列的执行,之后再手动触发一次RAF来模拟切回后的第一帧。具体实现步骤如下:

1. 初始化fake-timers时钟

先创建模拟时钟,禁止自动推进时间,确保我们能完全控制时间流:

const { clock } = sinon.useFakeTimers({
  now: Date.now(),
  shouldAdvanceTime: false,
});

2. 模拟切tab:跳转时间但不执行RAF

使用clock.setSystemTime()方法直接修改模拟系统时间——这个方法不会触发任何定时器或RAF回调,完美对应切tab时时间流逝但页面暂停执行的状态:

// 跳转1分钟(60000毫秒)
const targetTime = clock.now() + 60 * 1000;
clock.setSystemTime(targetTime);

3. 模拟切回tab:触发一次RAF执行

切回浏览器标签后,RAF会恢复执行,此时我们需要手动触发一次RAF队列中的回调,让它拿到跳转后的时间:

// 获取fake-timers内部维护的RAF任务队列
const rafCallbacks = clock.timers.requestAnimationFrame;

// 如果有等待执行的RAF回调,取出第一个并执行,传入当前模拟时间
if (rafCallbacks.length > 0) {
  const callback = rafCallbacks.shift();
  callback(clock.now());
}

完整示例

假设你有一个持续运行的RAF循环,完整模拟流程如下:

// 注册RAF循环
function rafLoop(timestamp) {
  console.log('当前帧时间:', timestamp);
  requestAnimationFrame(rafLoop);
}
requestAnimationFrame(rafLoop);

// 初始化模拟时钟
const { clock } = sinon.useFakeTimers({ now: Date.now(), shouldAdvanceTime: false });

// 模拟切tab,跳1分钟
clock.setSystemTime(clock.now() + 60000);

// 模拟切回tab,触发第一帧
const rafCallbacks = clock.timers.requestAnimationFrame;
if (rafCallbacks.length > 0) {
  const callback = rafCallbacks.shift();
  callback(clock.now()); // 此时输出的时间会是跳转后的时间
}

// 清理时钟
clock.restore();

这种方式完全模拟了切tab时时间静默流逝、切回后RAF首次执行拿到跳转后时间的场景,避免了clock.tick()或clock.tickAsync()逐帧执行RAF的问题。

内容的提问来源于stack exchange,提问作者trusktr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 15:07:37