非同步 JavaScript 時間操縱之術: setTimeout 與 setInterval
學會非同步操縱時間
在介紹到同步與非同步代碼時,時常會以 setTimeout
以及 setInterval
來模擬程式被非同步的執行,本文將會詳細講解其背後原理與實際上如何操作。
setTimeout
如果想要在一段時間後執行一段代碼會使用 setTimeout
,它是存在於 DOM API 中的方法,可達成:「在 x 毫秒後,執行 y 函式」的功能。
拿一些更為實際的案例來展示:小明得知晚餐煮好了,但他要打電腦,所以和家人說再一分鐘後就離開電腦去吃晚餐。
setInterval
setTimeout
只會執行一次,而 setInterval
則是會在輸入的間隔時間內不斷重複執行輸入的函式,它們有著一模一樣的語法:
取消倒數
要清除時間倒數,可以使用 clearInterval(timerId)
或 clearTimeout(timerId)
。每當使用以上方法時,就會拿到一筆「標識符 ID」,放入 clearTimeout
或 clearInterval
函式中即可終止整個計畫調用。
背後理論
一切都是如此的自然,但仔細想想似乎有些不合理的事情?
瀏覽器中 JavaScript 是以單一執行緒來同步執行程式的,白話來說就是一次只能執行一件事,那這樣要如何才能辦到同時間「等待」又「執行後續程式」的?
實際上,JavaScript 確實有執行 setTimeout
,只是提交了「等待」這件事給 Web API 處理,詳細可以在文章底部有我寫的另一篇文章:從動圖輕鬆入門非同步 JavaScript 可參考。
零延遲 Zero Delay
當把 setTimeout
的延遲設置為 0 秒時,並不意味著回呼函式中的內容會立即就被執行,實際上要考慮到 Call Stack 中還有沒有事要完成,該參數僅代表「要求執行環境處理所需的最少等待時間,而非一個保證時間。」
所以要做精確時間的等待最好不要使用 setTimeout
。
參考資料
- YouTube - What the heck is the event loop anyway? | Philip Roberts | JSConf EU
- PJCHENder - [JS] 理解 JavaScript 中的事件循環、堆疊、佇列和併發模式(Learn event loop, stack, queue, and concurrency mode of JavaScript in depth)
- MDN - 並行模型和事件循環