본문 바로가기
language/javascript

♻️ DOM 참조와 비동기 로직에서의 메모리 주의점 – 실무 중심 정리

by 죄니안죄니 2025. 5. 11.

♻️ DOM 참조와 비동기 로직에서의 메모리 주의점 – 실무 중심 정리

자바스크립트는 비동기 로직DOM 참조를 함께 사용할 때 메모리 누수가 자주 발생합니다.
이 글에서는 이벤트 리스너, setTimeout, 클로저, 비동기 콜백 등에서 발생할 수 있는 메모리 유지 원인과 방지 전략을 정리합니다.


1. 문제: DOM 요소가 제거됐는데 메모리에는 남아있다?


function init() {
  const el = document.getElementById("btn");
  el.addEventListener("click", () => {
    alert("clicked");
  });
  el.remove(); // ❌ 하지만 이벤트 리스너는 여전히 el을 참조
}

👉 이벤트 리스너 내부에서 el을 참조하면, 요소가 제거돼도 GC가 되지 않습니다.


2. 해결: 리스너 제거는 반드시!


function cleanup(el, handler) {
  el.removeEventListener("click", handler);
  el.remove(); // ✅ 이제 GC 가능
}

removeEventListener를 빼먹으면 메모리 누수의 대표적인 원인이 됩니다.


3. setTimeout / setInterval 안의 DOM 참조


const el = document.getElementById("box");
setTimeout(() => {
  el.style.display = "none"; // ❌ el이 계속 메모리에 남음
}, 5000);
✅ 해결 방법:

setTimeout(() => {
  const el = document.getElementById("box");
  if (el) el.style.display = "none";
}, 5000);

👉 필요할 때만 DOM을 다시 가져오고, 오래 참조하지 않도록 합니다.


4. 비동기 콜백에서 DOM 참조 유지


function fetchAndUpdate(el) {
  fetch("/api/data")
    .then(res => res.json())
    .then(data => {
      el.textContent = data.message; // ❌ el이 클로저로 묶임
    });
}
✅ 개선 방법:

function fetchAndUpdate(id) {
  fetch("/api/data")
    .then(res => res.json())
    .then(data => {
      const el = document.getElementById(id);
      if (el) el.textContent = data.message;
    });
}

👉 엘리먼트 참조는 짧게 유지하고, ID나 data-attr로 필요 시 다시 조회하는 패턴이 좋습니다.


5. MutationObserver나 IntersectionObserver

이런 관찰자 API도 콜백 내부에서 DOM을 계속 참조하면 누수가 발생할 수 있습니다.

✅ 반드시 해제 필요:

const observer = new MutationObserver(callback);
observer.observe(targetNode, { childList: true });

// 나중에 해제
observer.disconnect();

6. 메모리 누수 방지 체크리스트 ✅

  • ☑ 이벤트 리스너는 removeEventListener로 제거
  • ☑ 타이머(setTimeout, setInterval)는 clearTimeout, clearInterval 호출
  • ☑ 비동기 콜백 안에서는 DOM 참조 최소화
  • ☑ 필요 시 ID, data-attr로 DOM을 재조회
  • MutationObserver 등은 disconnect로 해제

📌 마무리

자바스크립트는 DOM과 비동기 처리가 밀접하게 얽혀 있기 때문에,
요소를 직접 참조하는 클로저나 콜백, 타이머는 메모리 누수를 유발할 수 있습니다.
코드를 작성할 때는 참조 범위를 최소화하고, 리스너/관찰자 해제를 습관화하는 것이 중요합니다.

이로써 챕터 8: 메모리 관리와 성능 최적화가 마무리되었습니다.
다음 챕터 9에서는 고급 함수 패턴과 함수형 프로그래밍 개념으로 넘어갑니다. 첫 글은 고차 함수(Higher-Order Function)의 개념과 예제입니다.

댓글