2010-02-23 107 views
18

我使用jQuery和做這樣的事情JavaScript的內存泄漏

DOM

<div id="parent"></div> 

JS

var _doSomeThing = function() 
{ 
    //some codes 
} 

$(function() 
{ 
    // appending div and binding methods to span 
    $('#parent').append('<span>1</span>'); 
    $('#parent').append('<span>2</span>'); 
    $('#parent span').bind('click', _doSomeThing); 
}); 

function _clearDiv() 
{ 
    //clear div 
    $('#parent').html(''); 
} 

//sometime in future, call clear div 
_clearDiv(); 

現在我的問題是,事件綁定到DOM,後來只是從DOM刪除元素導致內存泄漏?

如果是的話,該如何解決這個問題?

回答

19

jQuery的html方法試圖通過任何元件去除的事件處理程序以防止內存泄漏那由於在jQuery對象上調用.html('')而被刪除。

從1.4.2源

html: function(value) { 
    if (value === undefined) { 
     return this[0] && this[0].nodeType === 1 ? 
     this[0].innerHTML.replace(rinlinejQuery, "") : 
      null; 
    } 
    // See if we can take a shortcut and just use innerHTML 
    // THE RELEVANT PART 
    else if (typeof value === "string" && !rnocache.test(value) && 
     (jQuery.support.leadingWhitespace || !rleadingWhitespace.test(value)) && 
     !wrapMap[ (rtagName.exec(value) || ["", ""])[1].toLowerCase() ]) { 

     value = value.replace(rxhtmlTag, fcloseTag); 

     try { 
      for (var i = 0, l = this.length; i < l; i++) { 
       // Remove element nodes and prevent memory leaks 
       if (this[i].nodeType === 1) { 
        jQuery.cleanData(this[i].getElementsByTagName("*")); 
        this[i].innerHTML = value; 
       } 
      } 

     // If using innerHTML throws an exception, use the fallback method 
     } 
     catch(e) { 
      this.empty().append(value); 
     } 
    } 
    else if (jQuery.isFunction(value)) { 
     this.each(function(i){ 
      var self = jQuery(this), old = self.html(); 
      self.empty().append(function(){ 
       return value.call(this, i, old); 
      }); 
     }); 

    } 
    else { 
     this.empty().append(value); 
    } 
    return this; 
} 

我們可以看到,jQuery.cleanData()函數被調用。以下是一個

cleanData: function(elems) { 
    var data, id, cache = jQuery.cache, 
     special = jQuery.event.special, 
     deleteExpando = jQuery.support.deleteExpando; 

    for (var i = 0, elem; (elem = elems[i]) != null; i++) { 
     id = elem[ jQuery.expando ]; 

     if (id) { 
      data = cache[ id ]; 

      if (data.events) { 
       for (var type in data.events) { 
        if (special[ type ]) { 
         jQuery.event.remove(elem, type); 

        } else { 
         removeEvent(elem, type, data.handle); 
        } 
       } 
      } 

      if (deleteExpando) { 
       delete elem[ jQuery.expando ]; 

      } else if (elem.removeAttribute) { 
       elem.removeAttribute(jQuery.expando); 
      } 

      delete cache[ id ]; 
     } 
    } 
} 

這看起來在jQuery.cache對象有關的事件的任何事件類型屬性源對象有關主叫.html('')時將被刪除,並且刪除它們各自元素的數據對象的屬性。

要基本解釋標準事件綁定是如何工作的,當函數綁定爲使用jQuery在元素上引發的事件的處理函數時,會將數據對象作爲屬性添加到jQuery.cache對象。此數據對象包含一個事件屬性對象,該對象將具有在其上創建的屬性,其名稱與您希望綁定事件處理函數的事件類型匹配。這個屬性將包含一個函數數組,這個函數在元素上引發事件時應該被調用,所以事件處理函數被添加到這個數組中。如果這是針對事件類型和元素的第一個事件處理函數,則調用jQuery.event.handle函數(使用元素作爲上下文,以使函數執行上下文中的this將引用該元素)向瀏覽器使用addEventListener/attachEvent

當引發事件時,jQuery.event.handle函數將調用數據對象的events屬性對象的屬性中匹配事件類型和引發該事件的元素的所有函數。

因此,總之,html('')不應該導致內存泄漏,因爲一些防禦措施已經到位,以防止它們。

+0

@russ我認爲你是對的昨天我做了很多測試,並得出結論.html('');也會避免內存泄漏,而 JS的innerHTML =''會導致內存泄漏。 我想知道是jQuery使內部列表中的元素,我們已經調用$()綁定()函數(即綁定一些事件),以便在window.unload我們可以刪除這些事件或jQuery自動爲我們做到這一點。對此有任何想法。 – 2010-02-24 07:35:33

+0

jQuery自動綁定一個函數來刪除'window.onunload'上的事件處理程序,作爲初始腳本執行的一部分。你會在Sizzle代碼塊之前的1.4.2源代碼中找到相關的代碼 - http://code.jquery.com/jquery-1.4.2.js :) – 2010-02-24 17:46:00

+0

你是對的,即使是jquery 1.3.2版本清除事件綁定到窗口卸載的元素。 所以我認爲我們不必編寫我們的代碼來清除綁定事件以避免內存泄漏。 thanx – 2010-02-25 19:10:09

2

無法評論泄漏問題,但您可以簡單地使用.empty()而不是.html('')。這樣你就可以清理innerHTML並刪除任何綁定的事件處理程序。

1

您可以隨時使用$('#parent span').unbind();只是要確定

2

是的,因爲jQuery保持附加事件處理程序的列表,使脫鉤他們更容易和以明確解開他們爲你當頁面卸載(其在IE中更嚴重的內存泄漏)。 (Prototype也是如此,不能說其他庫)。解決方案是在刪除元素(直接或通過empty)之前解除它們。

0

由於您經常引用$('#parent'),因此您應該在全局範圍內創建對該對象的引用,以便jQuery不會在每個請求中不斷查找該對象。這樣做,你基本上緩存對象的引用,這將極大地減少內存使用。

_parent = $('#parent'); 

...

function(){ _parent.append('<span>1</span>'); } 

編輯:我從本文拾起此尖端上jQuery Performance Rules

+1

巨大?你有沒有分析內存使用前後驗證這一說法? – PatrikAkerstrand 2010-02-23 21:47:23

+0

我在jQuery應用程序上有太多內存泄漏,MSIE在10分鐘後會自行關閉。進行這一次調整後,泄漏消失並且記憶穩定在合理的量。 – 2010-02-23 22:24:14

+3

我不會稱之爲內存「泄漏」而不是緩存jQuery對象,但這種做法可能會導致糟糕的性能,這就是您在IE中遇到的情況,這種瀏覽器系列通常實現的功能更少本地方法('選擇器API','document.getElementsByClassName')比其他瀏覽器,因此需要依靠JavaScript DOM遍歷實現來實現相同的結果。我會盡量避免全局命名空間污染,因爲它們儘可能地在本地緩存jQuery對象的變量。 – 2010-02-23 22:44:28