定義
setTimeout()和setInterval()常被用來處理延時和定時任務。 setTimeout() 方法用於在指定的毫秒數後呼叫函數或計算表達式,而setInterval()則可以在每隔指定的毫秒數循環呼叫函數或表達式,直到clearInterval清除它。
從定義上我們可以看到兩個函數十分類似,只不過前者執行一次,而後者可以執行多次,兩個函數的參數也相同,第一個參數是要執行的code或句柄,第二個是延遲的毫秒數。
很簡單的定義,使用起來也很簡單,但有時候我們的程式碼並不是按照我們的想像精確時間被調用的,很讓人困惑
簡單範例
看個簡單的例子,簡單頁面在載入完兩秒後,寫下Delayed alert!
複製程式碼
程式碼如下:
setTimeout('document.write("Delayed alert!");', 2000);
複製程式碼
程式碼如下:
var num = 0;
var i = setInterval(function() {
num ;
document.write(date.getMinutes() ':' date.getSeconds() ': ' date.getMilliseconds() '
');
if (num > 10)
1000);
頁每隔1秒記錄一次目前時間(分鐘:秒:毫秒),記錄十次後清除,不再記錄。考慮到程式碼執行時間可能記錄的不是執行時間,但時間間隔應該是一樣的,看看結果
複製程式碼
程式碼如下:
:38:116
:39:130
:40:144
:41:158
:42:172
:43:158
:42:172
:43:1886
:44:200
:45:214
:46:228
:47:242
:48:256
為什麼>
時間間隔幾乎是1000毫秒,但不精確,這是為什麼呢?原因在於我們對JavaScript定時器有一個誤解,JavaScript其實是運行在單執行緒的環境中的,這意味著定時器只是計畫程式碼在未來的某個時間執行,而具體執行時機是不能保證的,因為頁面的生命週期中,不同時間可能有其他程式碼在控制JavaScript進程。在頁面下載完成後程式碼的運行、事件處理程序、Ajax回呼函數都是使用同樣的線程,實際上瀏覽器負責進行排序,指派某段程式在某個時間點運行的優先權。
我們把效果放大一下看看,加入一個耗時的任務複製程式碼
程式碼如下:
function test() {
for (var i = 0; i div.setAttribute( 'id', 'testDiv');
document.body.appendChild(div);
}
}
setInterval(test, 10) ;
var num = 0;
var i = setInterval(function() {
var date = new Date();
document.write(date.getMinutes() ' :' date.getSeconds() ':' date.getMilliseconds() '
');
if (num > 10)
我們又加入了一個定時任務,看看結果
複製程式碼
程式碼如下:
:9:222
:12:482
:16:8
:19:143
:22:631
:25:888
:28:631
:25:888
:28: 712
:32:381
:34:146
:35:565
:37:406
這下效果明顯了,甚至差距都超過了3秒,而且差距很不一致。
我們可以把JavaScript想像在時間線上運作。當頁面載入的時候首先執行的是頁面生命週期後面要用的方法和變數宣告和資料處理,在這之後JavaScript進程會等待更多程式碼執行。當進程空閒的時候,下一段程式碼會被觸發
除了主JavaScript進程外,還需要一個在進程下一次空閒時執行的程式碼佇列。隨著頁面生命週期推移,程式碼會按照執行順序加入佇列,例如當按鈕被按下的時候他的事件處理程序會被加入到佇列中,並在下一個可能時間內執行。接到某個Ajax回應時,回呼函數的程式碼會被加入到佇列。 JavaScript中沒有任何程式碼是立即執行的,但一旦進程空閒就盡快執行。定時器對佇列的工作方式是當特定時間過去後將程式碼插入,這並不意味著它會馬上執行,只能表示它盡快執行。 知道了這些後,我們就能明白,如果想要精確的時間控制,是不能依賴JavaScript的setTimeout函數的。
複製程式碼
複製程式碼
程式碼如下:
var my_ c ) { //.......... ; } }, 100);
但這個方式的問題在於定時器的程式碼可能在程式碼再次被加入佇列之前還沒有執行完成,結果導致迴圈內的判斷條件不準確,程式碼多執行幾次,之間沒有停頓。不過JavaScript已經解決這個問題,當使用setInterval()時,只有在沒有該定時器的其他程式碼實例時才將定時器程式碼插入佇列。這樣確保了定時器代碼加入到佇列的最小時間間隔為指定間隔。
這樣的規則帶來兩個問題
1.1. 某些間隔會被跳過
2.2.多個定時器的程式碼執行之間的間隔可能比預期要小
為了避免這兩個缺點,我們可以使用setTimeout()來實現重複的定時器
setTimeout(function () {
//code
}, interval)
這樣每次函數執行的時候都會建立一個新的定時器,第二個setTimeout()呼叫使用了agrument.callee 來取得目前實施函數的引用,並設定另一個新計時器。這樣做可以確保在程式碼執行完成前不會有新的計時器插入,並且下一次定時器程式碼執行之前至少要間隔指定時間,避免連續運作。
set document.getElementById('moveDiv');
var left = parseInt(div.style.left) 5;
if (left setTimeout(arguments.callee, 50);
🎜>這段定時器程式碼每次執行的時候,把一個div向右移動5px ,當座標大於200的時候停止。