この解答例はChatGPTによって生成されています,正しいかは自己判断で。

BFE.devでのAI解答例 - JavaScript コーディング問題
36. fake timer(setTimeout)を実装する

以下がJavaScriptのコードになります。

class FakeTimer {
  constructor() {
    this.timers = new Map()
    this.currentTimestamp = 0
  }
  
  getCurrentTimestamp() {
    return this.currentTimestamp
  }

  install() {
    const originalSetTimeout = window.setTimeout
    window.setTimeout = (func, delay, ...args) => {
      const timer = setTimeout(func, delay, ...args)
      this.timers.set(timer, {
        func,
        delay,
        created: this.currentTimestamp
      })
      return timer
    }
    
    const originalClearTimeout = window.clearTimeout
    window.clearTimeout = (timer) => {
      this.timers.delete(timer)
      originalClearTimeout(timer)
    }

    const originalDateNow = Date.now
    Date.now = () => this.currentTimestamp
  }

  uninstall() {
    window.setTimeout = setTimeout
    window.clearTimeout = clearTimeout
    Date.now = Date.now
  }

  tick(time) {
    if (time === undefined) {
      time = Math.max(1, ...Array.from(this.timers.values()).map((timer) => 
        (timer.created + timer.delay) - this.currentTimestamp
      ))
    }

    const remainingTimers = new Map()
    this.timers.forEach((timer, timerId) => {
      const elapsed = this.currentTimestamp - timer.created
      const remainingTime = Math.max(0, timer.delay - elapsed)
      if (remainingTime <= time) {
        timer.func()
      } else {
        remainingTimers.set(timerId, {
          ...timer,
          delay: remainingTime
        })
      }
    })

    this.timers = remainingTimers
    this.currentTimestamp += time
  }
}

この実装では、setTimeout()clearTimeout()、そしてDate.now() を上書きしています。setTimeout()は、実行予定の関数と経過時間を記録してタイマーIDを返します。clearTimeout()は、タイマーIDを引数にとって、対応する登録済みのタイマーを削除します。

tick() 関数は実装済みのタイマーを調べ、経過した時間に応じて適切なタイマーを実行します。一方、まだ経過時間が残っているタイマーは、再度登録してタイマー実行を予約します。time 引数が指定されている場合、 tick()が指定された時間まで進みます。

テストされているように、この実装によって setTimeout()clearTimeout() が経過時間を予測できることが期待されます。ただし、これらの関数が実行された時間を変更する必要性がある場合、これらの関数を呼び出す前に時間を変更する必要があります。