2011-07-21 32 views
13

假設我每10秒鐘就需要從服務器獲取一些數據。我想有一個通過AJAX獲取數據的函數,然後調用setTimeout的再次調用這個函數:遞歸'setTimeout'函數調用最終會殺死JS引擎嗎?

function GetData(){ 
    $.ajax({ 
     url: "data.json", 
     dataType: "json", 
     success: function(data){ 
     // do somthing with the data 

     setTimeout(GetData, 10000); 
     }, 
     error: function(){ 
     setTimeout(GetData, 10000); 
     } 
    }); 
} 

如果有人離開網頁全天開放,它可以讓成千上萬的遞歸函數調用。

我不想使用setInterval,因爲它沒有考慮到網絡延遲。如果網絡繁忙,處理請求需要15秒,我不想在AJAX超時之前再次提問。

處理需要定期調用的函數的最佳方法是什麼?

+0

對GetData的每個後續調用都將完全獨立於對方。任何給定的GetData執行運行完成後,其上下文將被銷燬,並在計時器到期時創建新的上下文。 –

+0

這可能會導致服務器在客戶端JavaScript之前出現問題。正如其他人所提到的那樣,您沒有調用堆棧問題,因爲setTimeout允許函數返回並從堆棧中移除。遞歸算法,但不是實際。 – aepheus

+0

這個問題正是我正在研究的問題。感謝您將它帶到這裏。 – shaosh

回答

21

沒有實際的遞歸,因爲GetData的調用被延遲,同時JavaScript上下文被銷燬。所以它不會使JS引擎崩潰。

對於您的代碼示例,這基本上是在JS引擎的水平會發生什麼:

  1. 初始化JS引擎
  2. 創建的GetData功能方面
  3. 執行的GetData語句,包括 「setTimeout的」
  4. 「setTimeOut」指示JS引擎在10秒內調用一個函數
  5. 銷燬GetData函數上下文
  6. 在這一點上,在內存使用方面,我們回到了第1步。唯一的區別是JS引擎存儲了對函數的引用以及何時調用它(讓我們稱這個數據爲「futureCall」)。
  7. 10秒後,重複步驟2.「futureCall」被銷燬。
+0

這個實現是否依賴於?或者這是在JavaScript的規範? – Robert

+0

規範中提到「永遠不會銷燬setTimeout被調用的上下文」。這不是一個遞歸,所以沒有任何理由會導致任何失敗,甚至是嚴重的錯誤。 –

+0

我還在包裹着這個......所以,如果我假定JS中的所有東西都作爲事件處理程序運行,那麼setTimeout只會觸發另一個要處理的事件。它獲得自己的堆棧/線程/進程/內存/一切。 – Robert