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