36. 实现一个 fake timer(setTimeout)

中等难度  -通过 / -执行

setTimeout 可以设定未来的任务,但是其执行时间并不精确。(Event Loop)。

大多数时候这都不是问题,但是在test的时候却有些头疼。

比如,5. 手写throttle()并支持leading 和 trailing 中我们就需要比较精确的测试。

你能否实现一个静态化的setTimeout()clearTimeout(),而不再有Event Loop的问题。这也正是FakeTimes 的用途。

“精确”的意思是,“假设所有的函数的执行耗时为0,同时时间戳从0开始,那么setTimeout(func1, 100)将会精确的在时间戳:100进行执行func1"。

你需要同时修改Date.now()来提供新的时间戳。

class FakeTimer {
  install() {
    // setTimeout(), clearTimeout(), and Date.now() 
    // are replaced
  }

  uninstall() {
    // restore the original APIs
    // setTimeout(), clearTimeout() and Date.now()
  }

  tick() {
     // run all the schedule functions in order
  }
}

输入的代码将会大概像这样进行测试。


const fakeTimer = new FakeTimer()
fakeTimer.install()

const logs = []
const log = (arg) => {
   logs.push([Date.now(), arg])
}

setTimeout(() => log('A'), 100)
// log 'A' at 100

const b = setTimeout(() => log('B'), 110)
clearTimeout(b)
// b is set but cleared

setTimeout(() => log('C'), 200)

expect(logs).toEqual([[100, 'A'], [200, 'C']])

fakeTimer.uninstall()

注意

测试的时候只会用到Date.now(),其他的时间相关的函数可以忽略。

注意特例。

(45)