2010-02-23 18 views
18

मैं jQuery का उपयोग कर रहा है और इसजावास्क्रिप्ट स्मृति लीक

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 फ़ंक्शन ईवेंट प्रकार से मेल खाने वाले डेटा ऑब्जेक्ट की ईवेंट प्रॉपर्टी ऑब्जेक्ट की संपत्ति पर सरणी में सभी कार्यों को कॉल करेगा और जिस तत्व पर ईवेंट उठाया गया था।

तो संक्षेप में, html('') मेमोरी लीक का कारण नहीं बनना चाहिए क्योंकि उन्हें रोकने के लिए कई रक्षात्मक उपायों की जगह है।

+0

@ रूस मुझे लगता है कि आप कल सही हैं मैंने बहुत परीक्षण किया है और निष्कर्ष निकाला है कि .html (''); मेमोरी लीक से भी बचाएगा, जबकि जेएस का आंतरिक HTML = '' मेमोरी लीक का कारण बन जाएगा। मुझे आश्चर्य है कि jquery तत्वों की एक आंतरिक सूची बनाता है जिस पर हमने $() बाइंड() फ़ंक्शन (यानी कुछ ईवेंट बाध्य) कहा है, ताकि window.unload पर हम उन ईवेंट को हटा सकते हैं या jquery यह स्वचालित रूप से हमारे लिए करता है। क्या इसका कोई विचार है। –

+0

jQuery स्वचालित रूप से आंत स्क्रिप्ट निष्पादन के हिस्से के रूप में 'window.onunload' पर ईवेंट हैंडलर को निकालने के लिए फ़ंक्शन को बांधता है। आपको सिज़ल कोड के ब्लॉक से पहले 1.4.2 स्रोत में प्रासंगिक कोड मिलेगा - http://code.jquery.com/jquery-1.4.2.js :) –

+0

आप सही हैं, यहां तक ​​कि jquery 1.3.2 विंडो अनलोड पर तत्वों के लिए बाध्य संस्करण स्पष्ट घटनाओं। इसलिए मुझे लगता है कि स्मृति मेमोरी लीक से बचने के लिए हमें बाध्य घटनाओं को साफ़ करने के लिए हमारे कोड लिखना नहीं है। thanx –

2

रिसाव समस्या पर टिप्पणी नहीं कर सकता है लेकिन आप .html('') के बजाय .empty() का उपयोग कर सकते हैं। इस तरह आप आंतरिक HTML को साफ करेंगे और किसी भी बाध्य ईवेंट हैंडलर को हटा देंगे।

1

तुम हमेशा $('#parent span').unbind(); उपयोग कर सकते हैं बस सुनिश्चित करने के

2

हाँ, क्योंकि jQuery जब पेज उतार दिया है उन्हें आसानी से unhooking और आदेश उन्हें स्पष्ट रूप से आप के लिए घृणाजनक में बनाने के लिए संलग्न ईवेंट हैंडलर्स की एक सूची रखता है (जो आईई में एक और गंभीर स्मृति रिसाव के आसपास काम करता है)। (तो प्रोटोटाइप करता है, अन्य libs के लिए बात नहीं कर सकता।) समाधान तत्वों को हटाने से पहले उन्हें खोलना है (या तो सीधे, या empty के माध्यम से)।

0

चूंकि आप लगातार $ ('# पैरेंट') का जिक्र कर रहे हैं, तो आपको वैश्विक वस्तु में उस ऑब्जेक्ट का संदर्भ बनाना चाहिए ताकि jQuery लगातार प्रत्येक अनुरोध पर ऑब्जेक्ट की तलाश न कर सके। ऐसा करने से, आप अनिवार्य रूप से ऑब्जेक्ट के संदर्भ को कैश कर रहे हैं, जो मेमोरी उपयोग पर काफी कटौती करेगा।

_parent = $('#parent'); 

...

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

संपादित करें: मैं jQuery Performance Rules

+1

जबरदस्त? क्या आपने इस दावे को सत्यापित करने के पहले और बाद में स्मृति उपयोग का प्रोफाइल किया है? – PatrikAkerstrand

+0

मुझे एक jQuery अनुप्रयोग पर इतनी सारी मेमोरी लीक हो रही थीं कि एमएसआईई 10 मिनट के बाद खुद को बंद कर देगा। यह एक समायोजन करने के बाद, लीक दूर चली गई और स्मृति उचित मात्रा में स्थिर हो गई। –

+3

मैं इसे "लीक" नहीं कहूंगा जो jQuery ऑब्जेक्ट्स को कैश नहीं कर रहा है, लेकिन एक ऐसा अभ्यास जो संभावित रूप से खराब प्रदर्शन का कारण बन सकता है, जो आपके जैसा लगता है कि आप IE में अनुभव कर रहे थे, ब्राउज़र परिवार जिसने आम तौर पर कम से कम लागू किया है अन्य विधियों की तुलना में मूल विधियों ('चयनकर्ता API ',' document.getElementsByClassName') और इसलिए एक ही परिणाम प्राप्त करने के लिए जावास्क्रिप्ट डीओएम ट्रैवर्सल कार्यान्वयन पर भरोसा करने की आवश्यकता है। मैं ग्लोबल नेमस्पेस प्रदूषण को उन चरों को स्कॉप करके भी कोशिश करूंगा जो आप jQuery ऑब्जेक्ट को यथासंभव स्थानीय रूप से कैश करते हैं। –

संबंधित मुद्दे