瀏覽器提供的計時器功能有 setTimeout
和setInterval
二種,我們用它們來延遲一段時間才執行一段程式。
計時器並不是 JavaScript 的功能,而是隸屬於window
物件底下的方法,因此在撰寫程式碼時,可省略window
物件名稱。會這樣說是因為在 Node.js 環境下也有計時器的功能,方法的名稱也是一樣,但作用和瀏覽器有一些不一樣的地方。這裡我們專注在探討瀏覽器的計時器。
var timeoutID = setTimeout(function(){}, 1000);
var intervalID = setInterval(function(){}, 1000)
clearTimeout(timeoutID);
clearInterval(intervalID);
建立計時器的方式都是先呼叫方法,再代入一個函式,以及一個時間,時間是以毫秒為單位,1秒鐘就是1000毫秒。
提到計時器一定要和前一篇文章的 event loop 一起來看。
console.log("start");
(function(){
console.log("bar");
setTimeout(function(){
console.log("foo");
}, 0);
})();
console.log("end");
在上面的範例中,或許有人會認為 console 中的訊息是:
"start"
"bar"
"foo"
"end"
立即函式跑完"bar"
之後,因為setTimeout
延遲的時間是0,所以立刻執行。事實上 console 訊息卻是這樣:
"start"
"bar"
"end"
"foo"
從 event loop 模型來看,整段程式在執行時正佔據 JavaScript call stack,setTimeout
事件會被瀏覽器接手,在時間到期時,將函式丟到 task queue 裡,在這裡的任務一定會等到 call stack 的任務完全清空後,才由 event loop 將排第一個的任務移到 call stack 執行。
"start"
, "bar"
, "end"
會先執行完,然後才由 event loop 從 task queue 裡把"foo"
叫到 call stack。
setTimeout
和setInterval
都會回傳一個計時器ID,我們可以使用clearTimeout
和clearInterval
二個方法清除計時器,只要代入ID值,但是要在計時器有效的狀態。也就是說一旦setTimeout
時間到把函式排進 task queue 之後,它就功成身退,這時也沒有必要再清除它。
雖然setTimeout
和setInterval
都會將函式排進 task queue 裡,但是它們有不同的地方。
setInterval
的計時器在設定的時間到的時候,會將函式排進 task queue 裡,但是如果 task queue 裡已經有上一次計時器排入的任務,setInterval
就不會再安排新的任務進去,繼續它的計時。如果是setTimeout
在函式裡又再回呼自己的話,還是會將函式排入 task queue。