setTimeout()和setInterval()的區別

一、定時器

通常我們使用setTimeout()和setInterval()來創建定時器。一般情況下setTimeout()用於延遲執行某方法或功能,setInterval()則一般用於刷新表單,對於一些表單的假實時指定時間刷新同步。setTimeout()在指定的毫秒數後就會執行,而setInterval()則在每隔指定的毫秒數執行。也就是說setTimeout()執行一次,而setInterval()可以循環執行。

很多人對Javascript的定時器存在誤解,認爲它們是線程,事實上,Javascript是運行於單線程的環境中的。定時器僅僅只是計劃代碼在未來的某個時間執行,執行時機是不能保證的。在Javascript中沒有任何代碼是立刻執行的,但一旦進程空閒則儘快執行。

給隊列添加代碼並不意味着對它立刻執行,而只能表示它會盡快執行。比如,設定一個150ms後執行的定時器不代表到了150ms代碼就立刻執行,它表示代碼會在150ms後被加入到隊列中。如果在這個時間點上,隊列中沒有其它東西,那麼這段代碼就會被執行,表面上看上去好像代碼就在精確指定的時間點上執行了。其它情況下,代碼可能明顯地等待更長事件才執行。

所以,關於定時器,要記住的最重要的一點是,指定的時間間隔表示何時將定時器的代碼添加到隊列,而不是何時實際執行代碼

二、setTimeout()

我們來看一個例子:

var btn = document.getElementById('mybtn');
btn.onclick = function(){
    setTimeout(function(){
        //執行某些操作
    },250);
//其它代碼
};

在這裏給一個按鈕設置了一個事件處理程序。事件處理程序設置了一個250ms後調用的定時器。點擊該按鈕後,首先將onclick事件處理程序假如隊列。該程序執行後才設置定時器,再有250ms後,指定的代碼才被添加到隊列中等待執行。

如果onclick事件處理程序執行了300ms,那麼定時器的代碼至少要在定時器設置之後的300ms後纔會被執行。隊列中所有的代碼都要等等Javascript進程空閒之後才能執行,而不管它們是如何添加到隊列中的

所以我們來看一下這段代碼:

console.log('one');
setTimeout(function(){
  console.log('two');
},0);
console.log('three');	
執行結果是什麼呢?答案就應該是one three two

三、setInterval()

使用setInterval()創建的定時器確保了定時器代碼規則地插入到隊列中。這個方式的問題在於,定時器代碼可能在代碼再次被添加到隊列之前還沒有完成執行,結果導致定時器代碼連續運行好幾次,而之間沒有任何停頓。

使用setInterval()創建定時器會有兩個問題:

(1)某些間隔會被跳過

(2)多個定時器的代碼執行之間的間隔可能會比預期的小

假設,某個onclick事件處理程序使用setInterval()設置了一個200ms間隔的重複定時器。如果事件處理程序花了300ms多一點的事件完成,同時定時器代碼也花了差不多的時間,就會同時出現跳過間隔且連續執行定時器代碼的情況

爲了避免setInterval()的這兩個缺點,可以使用鏈式setTimeout()調用

setTimeout(function () {
   // 處理中
    setTimeout(arguments.callee,interval);
},interval);

這個模式鏈式調用了setTimeout(),每次函數執行的時候都會創建一個新的定時器。第二個setTimeout()調用使用了arguments.callee來獲取對當前執行的函數的引用,併爲其設置另外一個定時器。這樣做的好處是,在前一個定時器代碼執行完之前,不會想隊列插入新的定時器代碼,確保不會有任何缺失的間隔。而且,可以保證在下一次定時器代碼執行之前,至少要等等指定的間隔,避免了連續的運行。

參考資料:

    《Javascript高級程序設計》    Nicholas C.Zakas著

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章