프론트엔드 성능 최적화를 위한 ‘이벤트 위임’ 전략
프론트엔드 개발을 하다 보면 마크업이 점점 복잡해지고, 사용자 인터랙션이 늘어남에 따라 이벤트 핸들러도 함께 늘어나는 현상을 자주 겪게 됩니다. 특히 대규모 UI를 다루거나, 반복되는 DOM 구조를 포함하는 웹 애플리케이션에서는 버튼 수십 개, 리스트 수백 개에 이벤트를 각각 등록해야 할지도 모릅니다. 이처럼 이벤트 리스너가 많아지면 단순히 메모리 소비가 늘어나는 것을 넘어, 렌더링 성능 저하, 유지보수의 어려움으로 이어질 수 있습니다.
이 문제를 해결할 수 있는 대표적인 패턴이 바로 이벤트 위임(Event Delegation)입니다.

이벤트 위임은 이벤트 버블링 특성을 활용하여, 여러 개의 하위 요소 각각에 이벤트를 등록하는 대신 상위 요소 하나에만 리스너를 걸어 효율적으로 이벤트를 처리하는 방식입니다.
이번 글에서는 이벤트 위임이 어떻게 동작하는지, 실제로는 어떤 장점을 제공하는지, 그리고 언제 위임을 쓰고 언제 직접 등록하는 것이 더 나은지에 대해 실무적인 관점에서 구체적인 예시와 함께 알아보겠습니다.
이벤트 위임이란?
이벤트 위임은 이벤트 처리를 ‘위임한다’라는 개념으로, 자식 요소가 아닌 공통 부모 요소에 이벤트 핸들러를 등록해, 하위 요소의 이벤트까지 처리하는 방식입니다. 반복되는 구조나 동적으로 생성되는 요소가 많을 때 특히 유용하며, DOM 이벤트의 버블링 덕분에 가능한 전략입니다.
1) 상위 요소에 이벤트를 등록해 하위 요소를 처리하는 방식
예를 들어, <ul> 태그 안에 수십 개의 <li> 항목이 있다고 해봅시다.

각 <li>에 일일이 클릭 이벤트를 붙이는 대신, 상위 요소인 <ul>에 단 하나의 이벤트 핸들러만 등록하고, 클릭 된 대상이 어떤 <li>인지 판단하여, 적절한 동작을 수행하도록 만드는 방식이죠.
const ul = document.querySelector("ul");
ul.addEventListener("click", (e) => {
if (e.target.tagName === "LI") {
console.log(`클릭된 항목: ${e.target.textContent}`);
}
});
여기서 e.target.tagName은 대문자로 반환되기 때문에 “LI”와 비교합니다. 소문자 “li”로 비교하면 조건이 항상 false가 되기 때문에 주의해야 합니다.
조금 더 실전적인 예시로, 쇼핑몰 상품 목록에서 .delete-button 클래스가 있는 삭제 버튼을 처리해 보겠습니다.
document.querySelector('#product-list').addEventListener('click', (e) => {
if (e.target.matches('.delete-button')) {
console.log('삭제됨');
}
});
이 코드에서는 .delete-button 클래스를 가진 버튼을 클릭했을 때만 이벤트가 동작하도록 e.target.matches()를 사용합니다. 이렇게 하면 상위 요소인 #product-list에 이벤트를 한 번만 등록해도, 하위에 있는 수많은 삭제 버튼들을 한 번에 제어할 수 있습니다.
2) 이벤트 버블링이란?
이벤트 위임의 기반이 되는 개념이 바로 이벤트 버블링입니다. 이벤트 버블링(Event Bubbling)은 DOM 요소에서 이벤트가 발생했을 때, 해당 이벤트가 DOM 트리를 따라 상위 요소로 순차적으로 전파되는 현상을 말합니다.
예를 들어, 안의 요소를 클릭하면 클릭 이벤트는 li 요소에서 발생한 뒤, ul, body, html, document 순으로 전달됩니다. 이 구조 덕분에 하위 요소에서 발생한 이벤트를 상위 요소에서도 감지할 수 있는데요. 이것이 바로 이벤트 위임이 가능해지는 이유입니다. 아래와 같은 HTML 구조를 예로 들어볼게요.
<ul id="menu">
<li class="item">홈</li>
<li class="item">소개</li>
<li class="item">문의</li>
</ul>
이 리스트에서 각각의 <li class=”item”>에 개별 이벤트를 등록하는 대신, 다음과 같이 <ul id=”menu”> 하나에만 이벤트를 등록할 수 있습니다.
document.getElementById('menu').addEventListener('click', (e) => {
const li = e.target.closest('.item');
if (li) {
console.log(`클릭한 항목: ${li.textContent}`);
}
});
이벤트는 실제로는 <li> 요소에서 발생했지만, 이 이벤트가 부모인 <ul>까지 전파되기 때문에 <ul>에서 감지하고 처리할 수 있습니다. closest() 메서드는 이벤트가 발생한 위치에서 가장 가까운 .item 클래스를 가진 상위 요소를 찾는 데 사용됩니다. 이러한 방식은 코드의 간결성과 유지보수성을 높이는 데 큰 도움이 되죠.
이벤트 위임의 장점
또한 이벤트 위임은 단순히 이벤트 등록 수를 줄이는 기술이 아닙니다. 성능, 유지보수, 확장성 측면에서도 다양한 이점을 제공합니다.
1) 반복 구조에서 핸들러 수 대폭 감소
이벤트 위임의 가장 큰 강점 중 하나는 바로 이벤트 핸들러의 수를 대폭 줄일 수 있다는 점입니다. 반복되는 UI 구조에서 각 요소마다 일일이 핸들러를 붙이는 방식은 브라우저 메모리에 부담을 줄 수 있고, 코드도 불필요하게 길어지기 마련입니다. 이와 달리 이벤트 위임을 활용하면 수십, 수백 개의 요소도 단 한 줄의 핸들러로 통합해서 관리할 수 있습니다.

예를 들어, 댓글 목록이나 쇼핑몰의 상품 카드처럼 수많은 항목이 반복되는 UI에서는 각 요소에 핸들러를 붙이는 것보다, 상위 컨테이너에 하나의 핸들러를 등록하는 편이 훨씬 효율적입니다.
2) 동적으로 생성된 요소에서도 자동 적용
또 다른 장점은 동적으로 생성되는 요소에도 별도의 핸들러를 붙이지 않아도 자동으로 동작한다는 점입니다. 다음 예제를 보시면 이해하기 쉬울 겁니다.
document.getElementById('todo-list').addEventListener('click', (e) => {
if (e.target.matches('.todo-delete')) {
e.target.parentElement.remove();
}
});
const newItem = document.createElement('li');
newItem.innerHTML = '새 할 일 <button class="todo-delete">삭제</button>';
document.getElementById('todo-list').appendChild(newItem);
이 코드는 기존에 등록된 핸들러로 새로 추가된 .todo-delete 버튼까지 제어할 수 있습니다. appendChild로 새롭게 생성된 요소에는 개별 이벤트를 등록하지 않았지만, 상위 요소에 등록된 이벤트 핸들러가 정상적으로 동작하는 것을 볼 수 있습니다. 이처럼 동적 UI에서 이벤트 위임은 유지보수와 성능 측면에서 매우 유리한 전략입니다.
언제 이벤트 위임을 쓰고, 언제 직접 등록할까?
이벤트 위임은 많은 상황에서 유용하지만, 모든 곳에 무조건 적용할 수 있는 만능 도구는 아닙니다. 상황에 따라 적절히 위임과 직접 등록 방식을 구분해야 합니다.
1) 반복되는 구조에서는 이벤트 위임
<ul>, <table>, <div class=”grid”>처럼 동일한 구조가 반복되는 경우라면 이벤트 위임을 사용하는 것이 좋습니다. 수십 개 이상의 요소에 동일한 이벤트를 등록해야 할 때는 위임 방식이 거의 필수입니다. 특히 리스트 항목이나 게시글 목록, 댓글 UI처럼 동적 요소가 반복되는 경우 위임 방식은 성능과 유지보수 측면 모두에서 탁월한 선택입니다.
2) 단일 또는 중요한 인터랙션은 직접 등록
반면, submit, scroll, drag, touchmove와 같은 이벤트는 예기치 않은 전파나 성능 문제를 막기 위해 직접 등록하는 것이 더 안전합니다. 로그인, 결제, 보안 관련 이벤트처럼 반드시 의도한 대상에서만 동작해야 하는 이벤트도 마찬가지입니다. 이 경우 이벤트 위임보다는 명확하게 해당 요소에 직접 핸들러를 등록하는 것이 더 바람직합니다.
3) 버블링이 중단되는 구조에서는 위임이 어려움
이벤트 버블링이 도중에 중단되는 구조에서는 위임이 제대로 작동하지 않습니다. 예를 들어, stopPropagation()이 호출되거나, Shadow DOM 같은 캡슐화된 환경에서는 이벤트가 상위 요소까지 전파되지 않기 때문에 이벤트 위임 방식이 무력화될 수 있습니다. 이럴 땐 위임이 아닌 직접 이벤트 등록 방식을 고려해야 합니다.
마치며
대규모 UI를 다룰 때, 반복되는 DOM 구조나 동적으로 생성되는 요소가 많다면, 이벤트 위임은 매우 유용한 전략입니다. 핸들러 수를 줄이고 성능을 개선할 수 있을 뿐만 아니라, 코드 유지보수와 확장성 측면에서도 뛰어난 이점을 제공합니다. 물론 모든 상황에 적용되는 것은 아니므로, 이벤트 전파 구조나 UI의 특성에 따라 위임과 직접 등록을 적절히 조합하는 것이 중요합니다.
마지막으로, 크롬 개발자 도구의 Performance와 Memory 탭을 활용해, 이벤트 핸들러 수, 실행 시간, GC 상태 등을 주기적으로 점검해 보는 것이 좋습니다. 우리가 무심코 붙인 이벤트 하나가 앱 성능에 큰 영향을 미칠 수 있습니다. 올바른 전략으로 이벤트를 다루는 습관이 쌓일수록, 더욱 빠르고 안정적인 프론트엔드 개발이 가능해질 것입니다.
©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.