了解 Sinon 时钟 `tick` 与 `tickAasync`

Understanding Sinon clock `tick` vs `tickAasync`

我想了解 clock.tickclock.tickAsync 之间的区别以及我应该在哪里使用它们。文档中的解释对我来说不是很清楚,通过查看代码本身,我仍然无法理解应该在何时何地使用每种方法。谁能帮我举个具体的代码示例?

The tickAsync() will also break the event loop, allowing any scheduled promise callbacks to execute before running the timers.

首先,我建议查看 video about event loop

如果短,ticktickAsync的区别是tick - 调用定时器同步tickAsync是 - 调用定时器 异步 允许在调用定时器

之前执行已解决的承诺

什么是同步。让我们看一下我们要测试的示例代码

function myFunction() {
  setTimeout(() => console.log('foo'), 1000)
  Promise.resolve().then(() => console.log('zoo'));
  console.log('bar')
}

和我们的同步测试代码

it('should test synchronously', () => {
   myFunction()
   tick(1000); // This would call scheduled timers synchronously ⚠️
   console.log('baz')
});
// print 'bar'
// print 'foo'
// print 'baz'
// print 'zoo'

现在让我们看一下相同的测试代码,但 tickAsync

it('should test synchronously', () => {
   myFunction()
   tickAsync(1000);
   console.log('baz')
});
// print 'bar'
// print 'baz' 
// print 'zoo' 
// print 'foo' 

如您所见,打印字符串的顺序发生了变化。 现在是相同的代码,但带有 await

it('should test synchronously', async () => {
   myFunction()
   await tickAsync(1000);
   console.log('baz')
});
// print 'bar'
// print 'zoo' 
// print 'foo' 
// print 'baz' 

要理解顺序改变的原因,您应该了解 micro tasks queue 和常规队列之间的区别。但是如果你看了上面 link 的视频,你应该已经明白了

P.S。 此外,您应该了解 sinon.useFakeTimers(); 将在自己的实现中替换 setTimeoutsetInterval,从而允许 sinon 完全控制传递给这些函数的计时器

这是一个非常粗略的近似值 sinon tick & tickAsync 是如何实现的

scheduledTimers = [];

function useFakeTimers() {
    global.setInterval = global.setTimeout = (fn) => {
        scheduledTimers.push(fn);
    }
}

function tick() {
    while (scheduledTimers.length) {
        scheduledTimers.shift()();
    }
}

function tickAsync() {
    // Call timers on the next tick
    return Promise.resolve().then(() => tick());
}