咱們都知道的是setTimout
是用來延遲一個簡單的動做的,然而,setInterval
的目的是用來重複執行某個動做的。php
而後,以上只是一半的事實。由於若是一個函數須要在一個間隔時間內重複的執行,你也能夠輕鬆的使用 setTimeout
設定延遲時間,被延遲執行的函數再進行自調用以此實現循環。ajax
因此,這裏有2種方法作一樣的事瀏覽器
一個用setInterval
服務器
var doStuff = function () { // Do stuff }; setInterval(doStuff, 1000);
一個用setTimeout
函數
var doStuff = function () { // DoStuff setTimeout(doStuff, 1000); }; setTimeout(doStuff, 1000);
// 若是你想當即執行函數,能夠這樣寫 var doStuff = function () { setTimeout(doStuff, 1000); } doStuff();
// 或者,更酷的方式,使用當即執行函數 (function doStuff () { // Do Stuff setTimeout(doStuff, 1000); }())
這必然致使下面兩個問題oop
問題:setInterval
和self-invoking setTimeout-loops
是能夠互相替換的嗎?
答案:不,固然不行。它們之間有着很細微的區別,可是若是想寫出好的代碼,這些細微的區別即是你想知道的事。網站
固然,接下我將會訴說的,第一,我將告訴你,咱們一般會遇到什麼樣的問題,第二,我將開始介紹它們之間細微的區別,這些區別將讓咱們從這兩個選擇中選出更具吸引力的那個一,第三,我將告訴你其實根本不用關心另外一個。而後。這裏是結論,setTimeout
將是更驚豔的那一個。接下來我將一點一點解釋。ui
首先:若是你試着重複調用的函數並不會化太多的時間來跑,那麼將不會有任何問題。即便如此,被調用的函數依然會出現2中不一樣的狀況:它既能夠在CPU上高集中的運行腳本,或者它也能夠在腳本流外先發出一個命令,並等待結果的到來。this
咱們主要研究先看第二種狀況。典型的即是ajax回調:你的腳本並不會等待服務器的響應,它會本身執行到最後,並讓回調函數來監聽ajax響應。code
如今,一些網站想要你保持實時更新,像Gmail,當你得到一封新的郵件時便會刷新你的郵箱。這裏服務端有新消息時便實時通知瀏覽器端的技術,一般叫作ajax輪詢。瀏覽器隔一段時間像服務器發送一個請求,詢問這裏有沒有須要更新的消息。
你也許會想,你很擅長使用setInterval
// 不要這樣作 var pollServerForNewMail = function () { $.getJSON('/poll_newmail.php', function (response) { if (response.newMail) { alert( "New mail. At last. You made me walk all the way to the server and back every " + "second for this, so if this isn't life-or-death, you got another thing coming." ); } }); }; setInterval(pollServerForNewMail, 1000);
其實像上面那樣寫並很差。由於請求發送出去到回來是須要時間的,可是這段時間誰能保證會比你設置的間隔時間要短呢?
一個典型的初學者的錯誤,會想將輪詢的間隔時間設置的長一點也許能夠解決這個問題。而後,事實是,不管你的間隔時間設的是多少,它依然有可能比,ajax響應的時間短。也就是說,有可能會發生,第一個請求還沒回來的狀況下,第二請求又已經發出去了。而你須要的是兩個請求之間有呼吸的空間,而setTimeout
即可以解決這個問題。
(function pollServerForNewMail() { $.getJSON('/poll_newmail.php', function (response) { if (response.newMail) { alert( "You have received a letter, good sir. " + "I will have a quick lie-down and be on my way shortly." ); } setTimeout(pollServerForMail, 1000); }); }());
在第一次發出請求,服務器響應以前,不會發生任何事。在響應回來時,纔會繼續發出第二個請求。固然,這也就意味着,兩個輪詢之間的時間超過了1秒,這也依賴於各類各樣的因素,像網速和服務器的響應速度等。可是,顯然的,這對咱們要作的事來講並不算是什麼問題。
這裏有兩個例子來更好的進行說明。
var timesRun = 0; var startTime = new Date().getTime(); var doStuff = function () { var now = new Date().getTime(); // 只跑5次 if (++timesRun == 5) clearInterval(timer); console.log('Action ' + timesRun + ' started ' + (now - startTime) + 'ms after script start'); // Waste some time for (var i = 0; i < 100000; i++) { document.getElementById('unobtanium'); } console.log('and took ' + (new Date().getTime() - now) + 'ms to run.'); }; var timer = setInterval(doStuff, 1000);
下面是結果
Action 1 started 1000ms after script start and took 8ms to run. Action 2 started 2000ms after script start and took 8ms to run. Action 3 started 3004ms after script start and took 6ms to run. Action 4 started 4002ms after script start and took 6ms to run. Action 5 started 5000ms after script start and took 6ms to run.
這裏並無多大的意外。這段代碼中間的循環花了一點時間,可是setInterval
依然很嚴格的執行了它的計劃。在一秒的間隔之間,開始時間之間並無一點空隙。
如今是setTimeout-loop
的例子
var timesRun = 0; var startTime = new Date().getTime(); var doStuff = function () { var now = new Date().getTime(); console.log('Action ' + (timesRun + 1) + ' started ' + (now - startTime) + 'ms after script start'); // Waste some time for (var i = 0; i < 100000; i++) { document.getElementById('unobtanium'); } console.log('and took ' + (new Date().getTime() - now) + 'ms to run.'); // Run only 5 times if (++timesRun < 5) { setTimeout(doStuff, 1000); } }; setTimeout(doStuff, 1000);
輸出結果
Action 1 started 1010ms after script start and took 8ms to run. Action 2 started 2021ms after script start and took 8ms to run. Action 3 started 3031ms after script start and took 5ms to run. Action 4 started 4037ms after script start and took 6ms to run. Action 5 started 5043ms after script start and took 6ms to run.
這裏也並無太多的意外。咱們已經知道setTimeout-loop
並不會嚴格的執行計劃,而是在函數下一次調用以前,會給函數它足夠的時間執行它裏面的代碼。
不要使用setInterval
,若是你在意你的時間。setTimeout-loop
能夠給你足夠的時間控制你的腳本和回調,