我试图理解
clock.tick
和 clock.tickAsync
之间的区别以及我应该在哪里使用它们。文档中的解释对我来说并不清楚,通过查看代码本身,我仍然无法理解应该在何时何地使用每种方法。谁能帮我提供一个具体的代码示例?
tickAsync() 还将中断事件循环,允许在运行计时器之前执行任何预定的 Promise 回调。
首先,我建议观看有关事件循环的视频。
如果很短,
tick
和tickAsync
之间的区别在于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' 👈
要理解顺序变化的原因,您应该了解微任务队列和常规队列之间的区别。但如果您观看了上面链接中的视频,您应该已经明白了😊
附注 另外,您应该了解
sinon.useFakeTimers();
将在自己的实现中替换 setTimeout
和 setInterval
,从而允许 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());
}