तत्वों को हटाने से पहले क्या मुझे इवेंट श्रोताओं को हटाने की आवश्यकता है?


84

अगर मेरे पास उन बच्चों के साथ माता-पिता तत्व हैं, जिनके पास इवेंट श्रोता हैं, तो क्या मुझे माता-पिता को साफ़ करने से पहले उन इवेंट श्रोताओं को निकालने की आवश्यकता है? (यानी, parent.innerHTML = '';) अगर वहाँ श्रोताओं एक तत्व से अनबाउंड नहीं हैं अगर यह DOM से हटा दिया गया है तो मेमोरी लीक हो सकता है?

जवाबों:


51

संक्षिप्त उत्तर: हाँ

दीर्घ उत्तर: अधिकांश ब्राउज़र इसे सही ढंग से संभालते हैं और उन हैंडलर को स्वयं हटा देते हैं। कुछ पुराने ब्राउज़र हैं (IE 6 और 7, अगर मुझे सही से याद है) जो इसे गड़बड़ कर रहे हैं। हां, मेमोरी लीक हो सकती है। आपको इस बारे में चिंता करने की ज़रूरत नहीं है, लेकिन आपको इसकी आवश्यकता है। इस दस्तावेज़ पर एक नज़र डालें ।


वास्तव में: हालांकि अधिकांश वर्तमान ब्राउज़र इससे ग्रस्त नहीं होंगे, लेकिन IE 7 अभी भी आमतौर पर उपयोग किया जाता है। जावास्क्रिप्ट में मेमोरी लीक पैटर्न पर भी एक नज़र डालें ।
मार्सेल कोर्पेल

7
क्या किसी को वर्तमान ब्राउज़र बाजार के लिए इसे अपडेट करने के लिए पर्याप्त ज्ञान है? या यह एक अलग सवाल के लायक है? IE7 मुझे लगा कि बहुत ज्यादा चरणबद्ध था , जबकि ie8 अभी भी चारों ओर लटका हुआ है। क्या IE8 परित्यक्त इवेंट श्रोताओं को संभालता है?
इदान मील्स

30
6 साल बाद, मुझे लगता है कि IE < 10इस बिंदु पर याहू और एओएल के अलावा अन्य साइटों पर जाने वाले किसी भी व्यक्ति द्वारा सुरक्षित रूप से पदावनत नहीं किया जा सकता है। कोई भी व्यक्ति जो इस बिंदु पर IE का उपयोग करता है, संभवतः भारतीय फोन घोटाले के शिकार होने की संभावना अधिक है या वायरस प्राप्त करने की समस्या है, क्योंकि इवेंट हैंडलर को ब्राउज़र के क्रैब को धीमा करने की समस्या है।
ब्रैडेन बेस्ट

70

बस यहाँ जानकारी को अद्यतन करने के लिए। मैं विभिन्न ब्राउज़रों का परीक्षण कर रहा हूं, विशेष रूप से iframe onload घटनाओं पर परिपत्र निर्भर इवेंट श्रोताओं के लिए मेमोरी लीक के लिए।

उपयोग किया गया कोड (jsfiddle मेमोरी परीक्षण में हस्तक्षेप करता है, इसलिए इस परीक्षण के लिए अपने स्वयं के सर्वर का उपयोग करें):

<div>
    <label>
        <input id="eventListenerCheckbox" type="checkbox" /> Clear event listener when removing iframe
    </label>
    <div>
        <button id="startTestButton">Start Test</button>
    </div>
</div>

<div>
    <pre id="console"></pre>
</div>

<script>

    (function() {
        var consoleElement = document.getElementById('console');
        window.log = function(text) {
            consoleElement.innerHTML = consoleElement.innerHTML + '<br>' + text;
        };
    }());

    (function() {
        function attachEvent(element, eventName, callback) {
            if (element.attachEvent)
            {
                element.attachEvent(eventName, callback);
            }
            else
            {
                element[eventName] = callback;
            }
        }

        function detachEvent(element, eventName, callback) {
            if (element.detachEvent)
            {
                element.detachEvent(eventName, callback);
            }
            else
            {
                element[eventName] = null;
            }
        }

        var eventListenerCheckbox = document.getElementById('eventListenerCheckbox');
        var startTestButton = document.getElementById('startTestButton');
        var iframe;
        var generatedOnLoadEvent;

        function createOnLoadFunction(iframe) {
            var obj = {
                increment: 0,
                hugeMemory: new Array(100000).join('0') + (new Date().getTime()),
                circularReference: iframe
            };

            return function() {
                // window.log('iframe onload called');
                obj.increment += 1;
                destroy();
            };
        }

        function create() {
            // window.log('create called');
            iframe = document.createElement('iframe');

            generatedOnLoadEvent = createOnLoadFunction(iframe);
            attachEvent(iframe, 'onload', generatedOnLoadEvent);

            document.body.appendChild(iframe);
        }

        function destroy() {
            // window.log('destroy called');
            if (eventListenerCheckbox.checked)
            {
                detachEvent(iframe, 'onload', generatedOnLoadEvent)
            }

            document.body.removeChild(iframe);
            iframe = null;
            generatedOnLoadEvent = null;
        }

        function startTest() {
            var interval = setInterval(function() {
                create();
            }, 100);

            setTimeout(function() {
                clearInterval(interval);
                window.log('test complete');
            }, 10000);
        }

        attachEvent(startTestButton, 'onclick', startTest);
    }());

</script>

यदि कोई मेमोरी रिसाव नहीं है, तो परीक्षण के चलने के बाद उपयोग की गई मेमोरी लगभग 1000kb या उससे कम बढ़ जाएगी। हालाँकि, यदि स्मृति रिसाव है, तो मेमोरी लगभग 16,000kb बढ़ जाएगी। ईवेंट श्रोता को हटाने से पहले हमेशा कम मेमोरी उपयोग (कोई लीक नहीं) होता है।

परिणाम:

  • IE6 - स्मृति रिसाव
  • IE7 - स्मृति रिसाव
  • IE8 - कोई स्मृति रिसाव
  • IE9 - स्मृति रिसाव (???)
  • IE10 - स्मृति रिसाव (???)
  • IE11 - कोई स्मृति रिसाव नहीं
  • एज (20) - कोई मेमोरी लीक नहीं
  • Chrome (50) - कोई मेमोरी लीक नहीं है
  • फ़ायरफ़ॉक्स (46) - कहना मुश्किल है, बुरी तरह से लीक नहीं करता है, इसलिए शायद सिर्फ अयोग्य कचरा कलेक्टर? बिना किसी स्पष्ट कारण के अतिरिक्त 4MB के साथ खत्म हो जाता है।
  • ओपेरा (36) - कोई स्मृति रिसाव नहीं
  • सफारी (9) - कोई स्मृति रिसाव नहीं

निष्कर्ष: ब्लीडिंग एज एप्लिकेशन शायद इवेंट श्रोताओं को नहीं हटा सकते हैं। लेकिन मैं अभी भी इसे अच्छी प्रथा मानता हूँ, झुंझलाहट के बावजूद।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.