---
# System prepended metadata

title: 'Use setinterval 忽略的精度差問題 '
tags: [筆記, JavaScript, setinterval]

---

## Use setinterval 忽略的精度差問題 

繼上一篇 [Use setinterval in React](https://hackmd.io/6sRDq-j1TWCTnKkhmUMYqg) 我們將 `setinterval` 封裝成 hook 去做使用。但在使用上時，我們原本的做法是通過與 `startTime` 進行比對來決定是否達到預期的延遲時間（delay），然而這種方式忽略了每次執行時產生的`微小差距`。這些差距會累積，導致最終的計時結果變得不準確，最終執行時間漸漸鈍化。

![image](https://hackmd.io/_uploads/ByiFXdBy1e.png)

為了解決這個問題，我們新增了一個 `accumulatedTime` 變數，用來記錄每次執行後所遺漏的時間，並在下次執行時與 startTime 進行時間差的 diff。這樣的改進確保了即使 setInterval 自身的精度存在偏差，計時仍能保持準確，尤其是在長時間運行的情況下。

> 這種方式有效地提高了 setInterval 的時間精度，避免了時間鈍化，並使其在需要高精度計時的場景中表現更穩定。

### Poo Poo Code
```javascript=
import { useEffect, useRef } from 'react'

export default (callback: () => void, delay: number | null): void => {
  const savedCallback = useRef<() => void>()
  const startTime = useRef<number>(0)
  const accumulatedTime = useRef<number>(0)

  useEffect(() => {
    savedCallback.current = callback
  }, [callback])

  useEffect(() => {
    if (delay === null) return

    startTime.current = Date.now() - accumulatedTime.current

    const tick = (): void => {
      const now = Date.now()
      const elapsed = now - startTime.current

      if (elapsed >= delay && savedCallback.current !== undefined) {
        savedCallback.current()
        startTime.current += delay
        accumulatedTime.current = elapsed - delay
      }
    }

    const id = setInterval(tick, Math.min(10, delay))

    return (): void => clearInterval(id)
  }, [delay])
}

```