2010-01-19 80 views
5

我正在編寫一個webapp(僅與Firefox兼容),它使用長輪詢(通過jQuery的ajax功能)從服務器向客戶端發送或多或少不斷的更新。我擔心整天或整夜都會長時間運行的影響。基本的代碼框架是這樣的:提高長輪詢Ajax性能

function processResults(xml) 
{ 
    // do stuff with the xml from the server 
} 

function fetch() 
{ 
    setTimeout(function() 
    { 
     $.ajax({ 
      type: 'GET', 
      url: 'foo/bar/baz', 
      dataType: 'xml', 
      success: function (xml) 
      { 
       processResults(xml); 
       fetch(); 
      }, 
      error: function (xhr, type, exception) 
      { 
       if (xhr.status === 0) 
       { 
       console.log('XMLHttpRequest cancelled'); 
       } 
       else 
       { 
        console.debug(xhr); 
        fetch(); 
       } 
      } 
     }); 
    }, 500); 
} 

(半秒「休眠」是爲了讓客戶端不錘,如果更新很快回來給客戶端的服務器 - 他們通常是)

一夜之間離開這個運行後,它往往使Firefox的抓取。我一直在想,這可能是由於我已經基本寫了一個無限遞歸函數而導致的大堆棧深度。但是,如果我使用Firebug並將斷點放入fetch,看起來情況並非如此。 Firebug向我展示的堆棧只有大約4或5幀深,即使在一小時之後。

一個我考慮的是改變了我的遞歸函數來一個迭代的解決方案,但我想不出我怎麼會插入延遲之間無紡 Ajax請求。我已經看過JS 1.7 "yield" keyword,但我無法把頭繞在它周圍,弄清楚這是否是我需要的。

最好的解決方案是定期進行一次硬刷新,比如說每小時一次?是否有更好的/更精簡的長輪詢設計模式,即使在運行8或12小時後也不會對瀏覽器造成傷害?或者我應該完全跳過長輪詢,並使用不同的「常量更新」模式,因爲我通常知道服務器對我有多頻繁響應?

回答

2

這也有可能是它的螢火。你是console.logging的東西,這意味着你可能有一個網絡監視器選項卡打開等,這意味着每個請求都存儲在內存中。

嘗試禁用它,看看是否有幫助。

+0

這對我有幫助! – JulienFr 2013-07-11 14:13:25

2

我懷疑內存從processResults()泄漏。

我在一個長輪詢的web應用程序中使用了非常類似的代碼,可以在沒有頁面刷新的情況下連續運行數週。

您的堆棧不應該很深,因爲fetch()會立即返回。你沒有一個無限遞歸循環。

您可能想要使用Firefox Leak Monitor Add-on來幫助您查找內存泄漏。

+0

我認爲這是另一種「打破」堆棧深度的方式,但我沒有看到在我的原始代碼中有'setTimeout'有任何不同的效果。 – 2010-01-19 16:16:17

+0

是的,但是你的堆棧不應該太深,因爲fetch()會立即返回,所以成功和錯誤函數很快就會退出堆棧。 – 2010-01-19 16:17:51

+0

我懷疑你的內存是從'processResults()'泄漏的。 – 2010-01-19 16:22:04

1

4-5堆棧深度是正確的。 setTimeout$.ajax是異步調用,它們立即返回。該回調稍後由瀏覽器調用一個空的調用堆棧。既然你不能以同步的方式實現長輪詢,你必須使用這種遞歸方法。沒有辦法讓它迭代。

我懷疑這個減慢的原因是,你的代碼中有內存泄漏。泄漏既可以是$.ajax的jQuery(不太可能),或在您的通話processResults

1

從方法本身內部調用fetch()是個壞主意。如果您期望在某些時候該方法將結束並且結果將開始發送給調用者,則會更好地使用遞歸性。問題是,當你遞歸調用方法時,它保持打開調用方法並使用內存。如果你只有3-4幀深,那是因爲jQuery或瀏覽器以某種方式「修復」你所做的事情。

最近發佈的jquery默認支持長輪詢。通過這種方式,您可以確定yhou不會因瀏覽器的智能而無法處理您的無限遞歸調用。當調用$.ajax()方法時,您可以使用下面的代碼進行長輪詢,並在新的呼叫前安全等待500毫秒。

function myLongPoll(){ 
    setTimeout(function(){ 
     $.ajax({ 
      type:'POST', 
      dataType: 'JSON', 
      url: 'http://my.domain.com/action', 
      data: {}, 
      cache: false, 
      success:function(data){ 

       //do something with the result 

      }, 
      complete: myLongPoll, 
      async : false, 
      timeout: 5000 
     }); 
    //Doesn't matter how long it took the ajax call, 1 milisec or 
    //5 seconds (timeout), the next call will only happen after 2 seconds 
    }, 2000); 

這樣你可以肯定的是,下一個開始前的$.ajax()呼叫被關閉。這可以通過在您的$.ajax()調用之前添加一個簡單的console.log()來證明。

+0

使用jQuery的'complete'回調與我的問題中的實現沒有顯着不同。這不是Java - 呼叫者從不需要顯式關閉XHR或其他資源。 – 2014-05-14 15:47:35