[javascript] DOM 요소가 제거되면 해당 리스너도 메모리에서 제거됩니까?

DOM 요소가 제거되면 리스너도 메모리에서 제거됩니까?



답변

최신 브라우저

일반 자바 스크립트

제거 된 DOM 요소에 참조가없는 경우 (참조가없는 참조) -요소 자체는 가비지 수집기 및 관련 이벤트 처리기 / 청취자에 의해 선택됩니다.

var a = document.createElement('div');
var b = document.createElement('p');
// Add event listeners to b etc...
a.appendChild(b);
a.removeChild(b);
b = null; 
// A reference to 'b' no longer exists 
// Therefore the element and any event listeners attached to it are removed.

하나; 여전히 상기 요소를 가리키는 참조가 있다면, 요소 및 그 이벤트 리스너는 메모리에 유지된다.

var a = document.createElement('div');
var b = document.createElement('p'); 
// Add event listeners to b etc...
a.appendChild(b);
a.removeChild(b); 
// A reference to 'b' still exists 
// Therefore the element and any associated event listeners are still retained.

jQuery

jQuery의 관련 메소드 (예 🙂 remove()가 정확히 같은 방식으로 작동 한다고 가정하는 것이 좋습니다 (예를 들어 remove()사용 된 것으로 간주 removeChild()).

그러나 이것은 사실이 아닙니다 . jQuery 라이브러리에는 실제로 DOM에서 제거 할 때 요소와 관련된 모든 데이터 / 이벤트를 자동으로 정리 하는 내부 메소드 (문서화되지 않았으며 이론상 언제든지 변경 될 수 있음)가 있습니다 cleanData() (여기서는이 메소드의 모양입니다 ) (통해이 될. remove(), empty(), html("")등).


이전 브라우저

오래된 브라우저, 특히 오래된 IE 버전은 이벤트 리스너가 연결된 요소에 대한 참조를 유지하기 때문에 메모리 누수 문제가있는 것으로 알려져 있습니다.

레거시 IE 버전 메모리 누수를 해결하는 데 사용되는 원인, 패턴 및 솔루션에 대한 자세한 설명을 보려면 Internet Explorer 누출 패턴 이해 및 해결에 대한이 MSDN 문서 를 읽어보십시오 .

이와 관련된 몇 가지 기사가 더 있습니다.

이 경우 리스너를 수동으로 직접 제거하는 것이 좋은 습관 일 것입니다 (메모리가 애플리케이션에 매우 중요하고 실제로 이러한 브라우저를 대상으로하는 경우에만).


답변

jQuery와 관련하여 :

.remove () 메소드는 DOM에서 요소를 가져옵니다. 요소 자체와 내부의 모든 요소를 ​​제거하려면 .remove ()를 사용하십시오. 요소 자체 외에도 요소와 관련된 모든 바인딩 된 이벤트 및 jQuery 데이터가 제거됩니다. 데이터와 이벤트를 제거하지 않고 요소를 제거하려면 .detach ()를 대신 사용하십시오.

참조 : http://api.jquery.com/remove/

jQuery v1.8.2 .remove()소스 코드 :

remove: function( selector, keepData ) {
    var elem,
        i = 0;

    for ( ; (elem = this[i]) != null; i++ ) {
        if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
            if ( !keepData && elem.nodeType === 1 ) {
                jQuery.cleanData( elem.getElementsByTagName("*") );
                jQuery.cleanData( [ elem ] );
            }

            if ( elem.parentNode ) {
                elem.parentNode.removeChild( elem );
            }
        }
    }

    return this;
}

분명히 jQuery는 node.removeChild()

이에 따르면 https://developer.mozilla.org/en-US/docs/DOM/Node.removeChild ,

The removed child node still exists in memory, but is no longer part of the DOM. You may reuse the removed node later in your code, via the oldChild object reference.

즉, 이벤트 리스너는 제거 될 수 있지만 node여전히 메모리에 존재합니다.


답변

이벤트 핸들러에서 클로저가있는 요소에 대한 참조를 유지하고 요소가 이벤트 핸들러에 대한 참조를 유지하는 경우 메모리 누수를보기 위해 주저하지 마십시오.

가비지 콜렉터는 순환 참조를 좋아하지 않습니다.

일반적인 메모리 누수 사례 : 개체에 요소가 있음을 인정합니다. 해당 요소는 핸들러를 참조합니다. 그리고 핸들러는 객체를 참조합니다. 객체는 다른 많은 객체를 나타냅니다. 이 개체는 컬렉션에서 참조를 제거하여 버린 것으로 생각되는 컬렉션의 일부였습니다. => 전체 객체와 객체가 참조 할 때까지 페이지가 종료 될 때까지 메모리에 남아 있습니다. => 예를 들어 객체 클래스에 대한 완전한 killing 메소드에 대해 생각하거나 mvc 프레임 워크를 신뢰해야합니다.

또한 Chrome 개발 도구의 유지 트리 부분을 사용하는 것을 망설이지 마십시오.


답변

다른 답변을 확장하는 중 …

위임 된 이벤트 핸들러는 요소 제거시 제거되지 않습니다.

$('body').on('click', '#someEl', function (event){
  console.log(event);
});

$('#someEL').remove(); // removing the element from DOM

이제 확인하십시오 :

$._data(document.body, 'events');


답변

와 관련 jQuery하여 다음과 같은 일반적인 메소드는 데이터 및 이벤트 핸들러와 같은 다른 구문도 제거합니다.

없애다()

요소 자체 외에도 요소와 관련된 모든 바인딩 된 이벤트 및 jQuery 데이터가 제거됩니다.

빈()

메모리 누수를 피하기 위해 jQuery는 요소 자체를 제거하기 전에 하위 요소에서 데이터 및 이벤트 핸들러와 같은 다른 구문을 제거합니다.

html ()

또한 jQuery는 해당 요소를 새 컨텐츠로 바꾸기 전에 하위 요소에서 데이터 및 이벤트 핸들러와 같은 다른 구성을 제거합니다.


답변

예, 가비지 수집기에서도 제거합니다. 그래도 레거시 브라우저에서는 항상 그런 것은 아닙니다.


답변