요소를 제거하기 전에 이벤트 리스너를 제거해야합니까?


84

이벤트 리스너가 바인딩 된 자식이있는 부모 요소가있는 경우 부모를 지우기 전에 해당 이벤트 리스너를 제거해야합니까? (즉, parent.innerHTML = '';) 이벤트 리스너가 DOM에서 제거 된 경우 요소에서 바인딩 해제되지 않으면 메모리 누수가 발생할 수 있습니까?

답변:


51

짧은 대답 :

긴 답변 : 대부분의 브라우저는이를 올바르게 처리하고 해당 처리기를 제거합니다. 이것을 엉망으로 만드는 일부 오래된 브라우저 (IE 6 및 7)가 있습니다. 예, 메모리 누수가있을 수 있습니다. 이것에 대해 걱정할 필요는 없지만해야합니다. 한 번 봐 가지고 이 문서를 .


사실 : 대부분의 최신 브라우저는 그다지 고통스럽지 않지만 IE 7은 여전히 ​​일반적으로 사용됩니다. 또한 JavaScript의 메모리 누수 패턴을 살펴보십시오 .
Marcel Korpel

7
누군가가 현재 브라우저 시장에서 이것을 업데이트 할만큼 충분히 알고 있습니까? 아니면 별도의 질문을 할 가치가 있습니까? IE7 나는 ie8 이 여전히 주위에 매달려있는 동안 거의 단계적으로 중단 되었다고 생각했습니다 . IE8은 버려진 이벤트 리스너를 처리합니까?
Aidan Miles

28
6 년이 지난 지금 IE < 10은 야후와 AOL이 아닌 다른 사이트를 방문하는 사람이 사용하지 않고 사용하지 않는 것으로 간주 될 수 있다고 생각 합니다. 이 시점에서 IE를 유일하게 사용하는 사람은 이벤트 처리기가 브라우저의 속도를 늦추는 문제보다 인도 전화 사기의 희생양이되거나 바이러스에 감염 될 가능성이 더 높습니다.
Braden Best

67

여기에서 정보를 업데이트하기 만하면됩니다. 저는 특히 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-메모리 누수 없음
  • Edge (20)-메모리 누수 없음
  • Chrome (50)-메모리 누수 없음
  • 파이어 폭스 (46)-말하기 어렵고, 유출이 심하게되지 않아서 비효율적 인 가비지 수집기일까요? 명백한 이유없이 추가 4MB로 완료됩니다.
  • Opera (36)-메모리 누수 없음
  • Safari (9)-메모리 누수 없음

결론 : 블리딩 엣지 애플리케이션은 이벤트 리스너를 제거하지 않으면 벗어날 수 있습니다. 그러나 성가심에도 불구하고 여전히 좋은 습관이라고 생각합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.