웹 애플리케이션 개발 과정에서 스크롤 이벤트, 윈도우 리사이징, 실시간 키 입력 등은 매우 짧은 시간 동안 수없이 반복되어 발생합니다. 이러한 고빈도 이벤트를 제어하지 않고 그대로 처리할 경우, 브라우저의 리소스 소모가 극심해지고 전체적인 성능 저하를 초래할 수 있습니다. 이를 해결하기 위해 사용되는 대표적인 프로그래밍 기법이 디바운싱(Debouncing)과 쓰로틀링(Throttling)입니다.
1. 디바운싱 (Debouncing)
디바운싱은 연이어 발생하는 이벤트를 하나의 그룹으로 묶어, 마지막 이벤트가 발생한 후 일정 시간이 지날 때까지 추가 이벤트가 없으면 해당 함수를 실행하는 방식입니다. 즉, 입력이 진행되는 동안에는 실행을 지연시키다가 '멈춤' 상태가 감지될 때 동작합니다.
- 작동 원리: 이벤트 발생 시 타이머를 설정하며, 타이머가 만료되기 전에 새로운 이벤트가 들어오면 기존 타이머를 취소하고 다시 설정합니다.
- 대표적 사례: 검색창의 자동 완성 기능(타이핑이 끝난 후 API 호출), 폼 유효성 검사, 브라우저 창 크기 조절 최종 결과 반영.
2. 쓰로틀링 (Throttling)
쓰로틀링은 이벤트를 일정한 시간 간격(Interval)으로 제한하여 실행하는 방식입니다. 이벤트가 아무리 빈번하게 발생하더라도, 설정한 주기 내에는 단 한 번만 함수가 호출되도록 보장합니다.
- 작동 원리: 함수가 한 번 실행되면 일정 시간 동안 잠금 상태가 되며, 해당 시간이 지난 후에야 다시 실행 가능한 상태가 됩니다.
- 대표적 사례: 무한 스크롤 페이지의 스크롤 위치 계산, 애니메이션 프레임 제어, 마우스 트래킹.
3. 두 기법의 핵심 차이점
디바운싱과 쓰로틀링의 가장 큰 차이는 실행 빈도와 시점입니다. 디바운싱은 여러 번의 이벤트를 단 한 번의 실행으로 압축하는 데 집중하며, 마지막 작업이 끝난 후 처리가 일어납니다. 반면, 쓰로틀링은 실행 횟수 자체를 조절하여 일정한 흐름을 유지하되 지속적인 피드백이 필요한 경우에 적합합니다.
4. JavaScript 구현 코드
디바운싱(Debounce) 구현 예시
function applyDebounce(action, delay) {
let timeoutId;
return function(...args) {
// 이전 대기 중인 작업을 취소하고 새로 시작
if (timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
action.apply(this, args);
}, delay);
};
}
쓰로틀링(Throttle) 구현 예시
function applyThrottle(action, interval) {
let isThrottled = false;
return function(...args) {
// 실행 중인 상태가 아니라면 실행 허용
if (!isThrottled) {
action.apply(this, args);
isThrottled = true;
// 지정된 시간이 지난 후 다시 실행 가능하도록 변경
setTimeout(() => {
isThrottled = false;
}, interval);
}
};
}
이러한 제어 기법을 적절히 선택하면 불필요한 서버 API 호출을 줄이고 클라이언트의 렌더링 부하를 최소화하여 사용자 경험을 크게 개선할 수 있습니다.