2013-12-19 19 views
1

因此,下面的代碼只處理ajax調用成功的情況,如果ajax調用失敗,它將被忽略,並且deferred.reject()將永遠不會被調用。因此,如果我們遇到失敗的案例,那麼jQuery中的任何事件監聽器會永遠存在,導致內存泄漏?我是否總是調用JQuery Deferred.resolve或Deferred.reject?

$.when(loadSomething).done(function() { 
    // ... 
}); 

function loadSomething() { 
    var deferred = $.Deferred(); 

    // Only deal with the success case, 
    // If the ajax call failed, it is ignored and the deferred.reject() will never be invoked. 
    // So if we meet the failed case, will there any event listener inside jQuery will be keeped 
    // forever? 
    ajaxCallToLoad(onResult); 

    function onResult() { 
     deferred.resolve(); 
    } 

    return deferred.promise(); 
} 
+1

如果你只是做一個Ajax調用,'$ .ajax' /'$ .post' /'$ .get' /'$ .getJSON'返回jqXHR對象,它是與遞延兼容方法,並自動爲您解決。所以你可以從'ajaxCallToLoad'返回對象,而不是創建另一個延遲。 –

+0

謝謝,有理由我無法控制'ajaxCallToLoad'的行爲。你的意思是,如果我創建了一個延遲對象,我應該總是可以確定稍後調用解析或拒絕?那可能會導致內存泄漏?我試圖閱讀Jquery的源代碼,但它確實很複雜...... –

+0

是否會導致內存泄漏取決於Deferred實現,但是最好總是解決或拒絕它。 –

回答

0

那麼,如果我們遇到失敗的案例,那麼jQuery裏面的任何事件監聽器會永遠存在,導致內存泄漏?

幾乎肯定不是。

但是,如果你這樣做,你明確地使用承諾語義,但然後打破承諾合同。這是不好的做法。你必須「最佳實踐」選項:

  1. 繼續使用承諾,但堅持合同。更新ajaxCallToLoad,以便它也通知您失敗,並在發生延遲時致電reject推遲。 (如果ajaxCallToLoad使用jQuery的$.ajax功能,你可以只使用jqXHR對象$.ajax回報;它實現了Promise

  2. 如果你不想履行承諾的合同,只是用一個正常的「成功」回調而不是承諾。

+0

感謝您的回放,我做了一些測試,把'$ .when($ .Deferred())。done(function(){})'進入一個循環,並檢查它使用的內存的chrome任務管理器,它上下大約96MB。看起來垃圾收集對它起作用。你的回答證明了,謝謝 –

0

要回答你的真正的問題,如果你保持到延遲的參考和/或任憑你是否無法解決或拒絕推遲在你的代碼某處答應你只會泄漏內存。如果沒有引用,那麼就會像正常一樣收集垃圾。

這就是說,我認爲在這種情況下,而不是手動構建延遲,您應該使用.then方法允許您轉換/篩選結果。爲了這個例子,我們創建一個名爲load的方法,它只是隨機地解析或拒絕延遲,類似於可能失敗的ajax請求。

function load() { 
    return $.Deferred(function(dfr) { 
     if (Date.now() % 2) { 
      dfr.resolve(1); 
     } 
     else { 
      dfr.reject("OHNO!"); 
     } 
    }).promise(); 
} 

您現在能夠以被使用。然後對其進行過濾,像這樣什麼:

var filteredResult = load().then(function(result) { 
    return result * 2; 
}); 

filteredResult現在是一個承諾,其中如果負載得到解決,雙打原來的結果,所以filterResult.done(console.log.bind(console))將打印2到控制檯。如果負載失敗/被拒絕,那麼失敗處理程序仍然可以正常工作。

相關問題