1. 程式人生 > >關於setInterval()和setTimeout()一些小總結

關於setInterval()和setTimeout()一些小總結

網頁編寫中常常會遇到使用定時器或者說是計時器的時候,中秋的阿里月餅事件鬧得沸沸揚揚。網上有據說是本人貼出來的程式碼,程式碼中也是應用了setInterval()計時器,通過獲取控制元件,設定計時器,來實現秒搶月餅的。當然,網上的程式碼不一定是阿里員工的,但利用計時器的原理應該是一樣的。

1.JavaScript的單執行緒模型

在說setInterval之前,先來了解一下JavaScript的單執行緒模型。JavaScript執行在瀏覽器中,單執行緒的處理它的任務佇列,這些任務可能包括一些普通函式和回撥函式。當有非同步事件發生時,比如滑鼠點選事件發生、定時器觸發事件發生、ajax請求完成回撥觸發等,js會將這些事件放入執行佇列,等當前程式碼執行完畢後,再去處理佇列中的事件。下面我們通過一個例子來進一步瞭解js的單執行緒。

function handleClick(){
    {耗時6ms}
}
function f(){
    {耗時3ms的操作4}
}
function init(){
    {耗時5ms的操作1}
    觸發click事件
    {耗時10ms的操作2}
    setInterval(f,10);
    {耗時5ms的操作3}
}

那麼現在我們來分析一下這個程式碼,首先執行init函式,操作1耗時5ms,接著觸發click事件,由於單執行緒所以handleClick被放入執行佇列中,然後操作2耗時10ms,接著觸發計時器操作,由於當前還有任務在執行,所以計時器操作也被放入執行佇列,最後執行操作3。

總結一下就是:

0-20ms:執行init函式

20-26ms:執行handleClick()函式

26-29ms:執行f,也就是setInterval,setInterval在15ms時被觸發,由於setInterval的設定每10ms執行一次f,也就是在25ms,35ms,45ms,55ms等時候執行。但是當25ms時,js執行緒正在處理handleClick函式,所以被延遲到26ms,也就是handleClick函式執行完成時再執行f

35-38ms:執行f

45-48ms:執行f

……

瞭解完js的單執行緒以後我們開始進入正題,setInterval()

2.setInterval()

語法:setInterval(code,millisec[,"lang"])

code:必須,要呼叫的函式或執行的程式碼串

millisec:必須,週期性執行或呼叫code之間的時間間隔,以毫秒計。

解釋:

setInterval的millisec指定的是開始執行code之間的間隔,但並不考慮code本身所消耗的時間,所以實際執行時,setInterval兩次執行之間的時間間隔會小於millisec所指定的時間。下面由一個例子來具體解釋一下。

setInterval("run()",1000);
function run(){
  {耗時500ms的操作}
}

那麼這個例子執行時,在等待1000ms之後,開始執行run(),run()執行完畢需要500ms。當run()執行完畢後,再過500ms時,將再次執行run()。因為setInterval指定的是開始執行的間隔,而不考慮執行任務本身所消耗的時間。所以實際執行時,兩次執行code的時間會小於定義的millisec。

那麼這種情況就很容易發生任務“堵塞”,比如當code定義的任務非常耗時,超過了millisec,那麼當code完成一次後就會立刻開始下一次code執行,因為任務進行了累積,在很短的時間內連續觸發。比如在程式碼中我們定義了ajax請求,那麼如果任務進行了累積,則很可能會產生集中發出ajax請求的情況。

為了解決這種累積問題,確保兩次執行之間有固定的時間間隔,我們可以不採取setInterval,而是採取setTimeout這種方法。

3.setTimeout()

與setInterval一樣,setTimeout也允許傳入兩個引數,一個code,一個millisec

語法:setTimeout(code,millisec)

code:必需。要呼叫的函式後要執行的 JavaScript 程式碼串。

millisec:必需。在執行程式碼前需等待的毫秒數。

但是setTimeout與setInterval不同的是,setTimeout() 只在millisec後執行 code 一次,而非多次執行。

為了實現多次呼叫code和保證兩次執行code之間有固定的時間間隔,同時也解決setInterval的累積問題,我們可以採用在 code 自身再次呼叫 setTimeout()。

下面通過例子來具體說明:

var number=0;
function numCount(){   
        number=number+1;   
	alert(number);   
	setTimeout(numCount,1000);
}
setTimeout(numCount,1000);
上面的例子的執行結果就是每一秒彈出一個對話方塊並顯示number,確保了兩次執行的間隔是1000ms。

對於setInterval的使用,html5規定,millisec的最小值為10,也就是兩次code的執行間隔最短不能小於10ms,小於10ms 的時間間隔也會被調整到10ms。

在實際應用中,當遇到需要定時器時,建議大家儘量避免setInterval,這樣會減少一些不必要的問題。可以利用setTimeout的巢狀來替代setInterval。

如需轉載請註明出處。