定時器(timer)

setTimeout() 與 setInterval()

setTimeout()

定義 : 用於在指定的毫秒數後呼叫函式或計算表示式(延遲)

  綁定在瀏覽器 window 的一個方法,可以透過 setTimeout 指定一段程式碼或函式在多少毫秒(ms)後執行,並回傳此定時器的編號。可以透過 clearTimeout 取消程式碼的執行。 例如:

// 函式會將第一個參數字串使用eval轉換為可執行之程式碼
// 三秒後在 console 印出 "test123"
setTimeout('console.log("test123");',3000);
// 你也可以寫成function
setTimeout(function(){console.log('test123');},3000);

setTimeout()執行方法其實是將須執行程式碼加入任務佇列,直到輪到此程式碼執行時,檢查時間是否到達,若到達則執行程式碼。 舉例來說:

// 單純執行這段程式碼,可以看到實際所執行任務的時間
var startTime=new Date();
setTimeout(function(){console.log(new Date()-startTime);},100);
for(var i=0; i<1000000000; i++){}

可以發現 setTimeout 所設定的程式碼,會因為目前任務佇列所執行的程式碼而可能發生延誤執行的狀況。

var startTime=new Date();
var func = function(){
console.log('start: ' + (new Date()-startTime));
for(var i=0; i<1000000000; i++){};
console.log('end: ' + (new Date()-startTime));
setTimeout(func,100);
};
setTimeout(func,100);
// start: 2515
// end: 3457
// start: 3558
// end: 4503
// start: 4604
// end: 5543
// ....

上面這段程式碼,可以看到執行 funcendstart 時間基本上是符合我們所設定的 100 ms。

setInterval()

定義 : 在播放動畫的時,每隔一定時間就呼叫函式,方法或物件(週期)

  綁定在瀏覽器 window 的一個方法,可以透過 setInterval 指定一段程式碼或函式定時在多少毫秒(ms)後執行,並回傳此定時器的編號。可以透過 clearInterval 取消程式碼的執行。 大致用法與 setTimeout 相同,只差在定時執行,因此這邊我們同樣測試延遲執行的問題。

var startTime=new Date();
setInterval(function(){console.log(new Date()-startTime);},100);
for(var i=0; i<1000000000; i++){}

可以發現與 setTimeout 一樣是有延遲的狀況發生。

var startTime=new Date();
var func = function(){
console.log('start: ' + (new Date()-startTime));
for(var i=0; i<1000000000; i++){}
console.log('end: ' + (new Date()-startTime));
};
setInterval(func,100);
// start: 2520
// end: 3465
// start: 3466
// end: 4409
// start: 4409
// end: 5350
// start: 5351
// end: 6291
// start: 6292

上面這段程式碼的執行結果,與上面的 setTimeout 比較,你會發現 setInterval 的 endstart 時間跳動非常大,並不是我們所設定的 100 ms。 由於 setInterval 是一開始就標定了執行時間點,當所註冊的函式(func)超過執行的時間點,結束時則會馬上觸發(func),因此並不會是固定的 100 ms。

結論

最後,利用前面提到的延遲執行(將 setTimeout 與 setInterval 事件放進 task queue)特性,我們可以應用在程式碼執行的順序(比如等 innerHTML 執行完才 document.getElementById)。 舉例來說:

setTimeout(function() {
console.log("想最後執行的一段程式碼(getElementById)");
}, 0);
function a(x) {
console.log("a() 開始 innerHTML");
b(x);
console.log("a() 結束 innerHTML");
}
 
function b(y) {
console.log("b() 開始");
console.log("傳入的值" + y);
console.log("b() 結束");
}
console.log("程式碼開始");
a(42);
console.log("程式碼結束");
 
// 執行結果:
// 程式碼開始
// a() 開始 innerHTML
// b() 開始
// 傳入的值42
// b() 結束
// a() 結束 innerHTML
// 程式碼結束
// 想最後執行的一段程式碼(getElementById)

Last updated