關於 setTimeout 與 setInterval,你須要知道的一切

咱們都知道的是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能夠給你足夠的時間控制你的腳本和回調,

相關文章
相關標籤/搜索