javascript中的setInterval()和setTimeout()用法比較

來源:互聯網
上載者:User

標籤:

setTimeout()和setInterval() 何時被調用執行 定義

setTimeout()和setInterval()經常被用來處理延時和定時任務。setTimeout() 方法用於在指定的毫秒數後調用函數或計算運算式,而setInterval()則可以在每隔指定的毫秒數迴圈調用函數或運算式,直到clearInterval把它清除。

從定義上我們可以看到兩個函數十分類似,只不過前者執行一次,而後者可以執行多次,兩個函數的參數也相同,第一個參數是要執行的code或控制代碼,第二個是延遲的毫秒數。

很簡單的定義,使用起來也很簡單,但有時候我們的代碼並不是按照我們的想象精確時間被調用的,很讓人困惑

簡單樣本

看個簡單的例子,簡單頁面在載入完兩秒後,寫下Delayed alert!

setTimeout(‘document.write("Delayed alert!");‘, 2000);

看起來很合理,我們再看個setInterVal()方法的例子

按 Ctrl+C 複製代碼

按 Ctrl+C 複製代碼

頁面每隔1秒記錄一次目前時間(分鐘:秒:毫秒),記錄十次後清除,不再記錄。考慮到代碼執行時間可能記錄的不是執行時間,但時間間隔應該是一樣的,看看結果

43:38:11643:39:13043:40:14443:41:15843:42:17243:43:18643:44:20043:45:21443:46:22843:47:24243:48:256

 

為什麼

時間間隔幾乎是1000毫秒,但不精確,這是為什麼呢?原因在於我們對JavaScript定時器存在一個誤解,JavaScript其實是運行在單線程的環境中的,這就意味著定時器僅僅是計劃代碼在未來的某個時間執行,而具體執行時機是不能保證的,因為頁面的生命週期中,不同時間可能有其他代碼在控制JavaScript進程。在頁面下載完成後代碼的運行、事件處理常式、Ajax回呼函數都是使用同樣的線程,實際上瀏覽器負責進行排序,指派某段程式在某個時間點啟動並執行優先順序。

我們把效果放大一下看看,添加一個耗時的任務

function test() {            for (var i = 0; i < 500000; i++) {                var div = document.createElement(‘div‘);                div.setAttribute(‘id‘, ‘testDiv‘);                document.body.appendChild(div);                document.body.removeChild(div);            }        }        setInterval(test, 10);        var num = 0;        var i = setInterval(function() {            num++;            var date = new Date();            document.write(date.getMinutes() + ‘:‘ + date.getSeconds() + ‘:‘ + date.getMilliseconds() + ‘<br>‘);            if (num > 10)                clearInterval(i);        }, 1000);

我們又加入了一個定時任務,看看結果

47:9:22247:12:48247:16:847:19:14347:22:63147:25:88847:28:71247:32:38147:34:14647:35:56547:37:406

這下效果明顯了,差距甚至都超過了3秒,而且差距很不一致。

我們可以可以把JavaScript想象成在時間軸上運行。當頁面載入的時候首先執行的是頁面生命週期後面要用的方法和變數聲明和資料處理,在這之後JavaScript進程將等待更多代碼執行。當進程閒置時候,下一段代碼會被觸發

除了主JavaScript進程外,還需要一個在進程下一次空閑時執行的代碼隊列。隨著頁面生命週期推移,代碼會按照執行順序添排入佇列,例如當按鈕被按下的時候他的事件處理常式會被添加到隊列中,並在下一個可能時間內執行。在接到某個Ajax響應時,回呼函數的代碼會被添加到隊列。JavaScript中沒有任何代碼是立即執行的,但一旦進程空閑則儘快執行。定時器對隊列的工作方式是當特定時間過去後將代碼插入,這並不意味著它會馬上執行,只能表示它儘快執行。

知道了這些後,我們就能明白,如果想要精確的時間控制,是不能依賴於JavaScript的setTimeout函數的。

重複的定時器

使用 setInterval() 建立的定時器可以使代碼迴圈執行,到有指定效果的時候,清除interval就可以,如下例

var my_interval = setInterval(function () {            if (condition) {                //..........            } else {                clearInterval(my_interval);            }        }, 100);

但這個方式的問題在於定時器的代碼可能在代碼再次被添加到隊列之前還沒有執行完成,結果導致迴圈內的判斷條件不準確,代碼多執行幾次,之間沒有停 頓。不過JavaScript已經解決這個問題,當使用setInterval()時,僅當沒有該定時器的其他代碼執行個體時才將定時器代碼插入隊列。這樣確 保了定時器代碼加入到隊列的最小時間間隔為指定間隔。

這樣的規則帶來兩個問題

  1. 1. 某些間隔會被跳過

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

為了避免這兩個缺點,我們可以使用setTimeout()來實現重複的定時器

setTimeout(function () {            //code            setTimeout(arguments.callee, interval);        }, interval)

這樣每次函數執行的時候都會建立一個新的定時器,第二個setTimeout()調用使用了agrument.callee 來擷取當前實行函數的引用,並設定另外一個新定時器。這樣做可以保證在代碼執行完成前不會有新的定時器插入,並且下一次定時器代碼執行之前至少要間隔指定 時間,避免連續運行。

setTimeout(function () {            var div = document.getElementById(‘moveDiv‘);            var left = parseInt(div.style.left) + 5;            div.style.left = left + ‘px‘;            if (left < 200) {                setTimeout(arguments.callee, 50);            }        }, 50);

這段定時器代碼每次執行的時候,把一個div向右移動5px,當座標大於200的時候停止。


javascript中的setInterval()和setTimeout()用法比較

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.