---
# System prepended metadata

title: '[Web API] setTimeout & setInterval'
tags: [Web API]

---

# [Web API] setTimeout & setInterval


###### tags: `Web API`


## 計時器
### setTimeout
* 延遲指定的時間後，才執行程式碼，只執行一次
* 寫法：`const timeoutID = setTimeout(function[, delay, param1, …, paramN])`
  * 回傳的 id 數值：可用在取消計時器上
  * 第一個參數可以是字串，但不建議此寫法，可能有安全性問題
  * delay：延遲時間（毫秒）。若沒寫的話預設是 0，但不代表立刻執行，而是盡快執行，假設瀏覽器正在處理使用者輸入或其他事件，處理完才會執行

```javascript
setTimeout(() => {console.log('setTimeout 1');}, 1000);
setTimeout('console.log("setTimeout 2")', 1000);
setTimeout(console.log('setTimeout 3'), 1000); 

// setTimeout 3
// setTimeout 1
// setTimeout 2
```
:::warning
`setTimeout(console.log('setTimeout 3'), 1000);` 不會等 1000ms，而是立刻執行。
因為判斷不是 function 後會嘗試當作字串處理，故會把 `console.log('setTimeout 3')` 執行後的回傳值轉為字串，所以實際上是 `setTimeout('undefined', 1000);`
:::

### setInterval
* 固定延遲指定的時間後，才執行程式碼，不斷重複執行
* 若程式碼執行時間大於延遲時間，建議改用 `setTimeout()`
* 寫法：`const intervalID = setInterval(function[, delay, arg1, …, argN]);`
  * 回傳的 id 數值：可用在取消計時器上
  * 第一個參數可以是字串，但不建議此寫法，可能有安全性問題
  * delay：延遲時間（毫秒）。若沒寫的話預設是 0，但不代表立刻執行，而是盡快執行，假設瀏覽器正在處理使用者輸入或其他事件，處理完才會執行


## 取消計時器
### clearTimeout
* 取消 `setTimeout()`，須在延遲指定的時間還未到時才有效
* 寫法：`clearTimeout(timeoutID)`

### clearInterval
* 取消 `setInterval()`
* 寫法：`clearInterval(intervalID)`


## 注意事項
### 時間差問題
使用 `setTimeout()` 或 `setInterval()` 計算時間會產生誤差，無論如何優化，誤差都會存在

> 可以透過一些手法來降低誤差，像是一開始就先計算 client 的時間與 server 端的時間差，並定期與 server 端做時間同步修正，使誤差維持在最小可接受範圍內等。
> 如果是要執行動畫，則建議用 [requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame "Window: requestAnimationFrame() method - Web APIs | MDN") 來取代 `setTimeout()` 或 `setInterval()`。
> [name=Kuro Hsu] [time=Feb 23, 2019 18:12] [color=#87cefa] [談談 JavaScript 的 setTimeout 與 setInterval](https://kuro.tw/posts/2019/02/23/%E8%AB%87%E8%AB%87-JavaScript-%E7%9A%84-setTimeout-%E8%88%87-setInterval/ "談談 JavaScript 的 setTimeout 與 setInterval | Kuro's Blog")

```javascript=
const start = new Date().getTime();

const id = setTimeout(() => {
    const end = new Date().getTime();
    console.log('id: ', id);
    console.log(`time elapsed: ${start - end} ms`);
    console.log('start: ', start);
    console.log('end: ', end);
}, 1000);

// id:  2142
// time elapsed: -1002 ms
// start:  1643965712649
// end:  1643965713651
```

### this 指向問題
:::info
* [setTimeout() - The "this" problem](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#the_this_problem "setTimeout() global function - Web APIs | MDN")
* [setInterval() - The "this" problem](https://developer.mozilla.org/en-US/docs/Web/API/setInterval#the_this_problem "setInterval() global function - Web APIs | MDN")
* [关于setInterval和setTImeout中的this指向问题](https://www.cnblogs.com/zsqos/p/6188835.html "关于setInterval和setTImeout中的this指向问题 - 陌路黄昏后 - 博客园")
:::

向 `setTimeout`、`setInterval` 傳遞 method 或 function 時，this 的指向可能跟預期不同

### 解決方法
1. 使用包裝函式 (Wrapper function)，也可以用箭頭函式（Arrow function）
2. 使用 `bind()`


## 參考資料
* [談談 JavaScript 的 setTimeout 與 setInterval](https://kuro.tw/posts/2019/02/23/%E8%AB%87%E8%AB%87-JavaScript-%E7%9A%84-setTimeout-%E8%88%87-setInterval/ "談談 JavaScript 的 setTimeout 與 setInterval")
* [setTimeout() global function - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout "setTimeout() global function - Web APIs | MDN")
* [setInterval() global function - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/setInterval "setInterval() global function - Web APIs | MDN")
* [clearTimeout() global function - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout "clearTimeout() global function - Web APIs | MDN")
* [clearInterval() global function - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval "clearInterval() global function - Web APIs | MDN")


---

:::info
建立日期：2022-02-04
更新日期：2023-09-10
:::