# [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
:::