如何用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
相关产品推荐
相关产品推荐

