Skip to content

[javascript] 深入了解 setTimeout() 與 setInterval() 的不同之處

Published: at 05:27 AM

許多人認為 setTimeout() 與 setInterval() 的差別僅是一個僅會執行一次,另一個則會自動重複執行這樣的差別。

但其中其實還有許多值得深入與研究的不同之處,這篇將由淺至深地介紹兩者的差別。

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

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

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

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

    接下來我們再測試以下程式碼

    [javascript] var startTime=new Date(); setTimeout(function(){console.log(new Date()-startTime);},100); for(var i=0; i<1000000000; i++){} [/javascript]

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

    再來我們測試一段 setTimeout 執行時間的程式碼

    [javascript] 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 // … [/javascript]

    上面這段程式碼,可以看到執行 func 的 endstart 時間基本上是符合我們所設定的 100 ms。(待會與下方 setInterval 比較)

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

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

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

    接下來我們再測試以下程式碼

    [javascript] 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 [/javascript]

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

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

[javascript] 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) [/javascript]

參考資料:

http://www.jeffjade.com/2016/01/10/2016-01-10-javacript-setTimeout/

http://www.jeffjade.com/2016/01/10/2016-01-10-javaScript-setInterval/