디바운스
연속으로 발생하는 이벤트를 그룹화하여, 마지막 이벤트 이후 일정 시간이 지나야 한 번만 실행되도록 제어하는 기법입니다.
동작 원리
이벤트 발생 타임라인 (대기 시간: 300ms)
입력: ㅎ ㅏ ㄴ ㄱ ㅜ ㄱ (연속 타이핑)
↓ ↓ ↓ ↓ ↓ ↓
타이머: 리셋 리셋 리셋 리셋 리셋 시작 → 300ms 경과 → 실행! ("한국" 검색)
매 이벤트마다 타이머를 리셋하고, 마지막 이벤트 이후 대기 시간이 지나면 단 한 번 실행됩니다.
대표 사용 사례
| 사용 사례 | 설명 |
|---|---|
| 검색 자동완성 | 타이핑이 멈춘 후 API 호출 |
| 윈도우 리사이즈 | 리사이즈가 끝난 후 레이아웃 재계산 |
| 버튼 중복 클릭 방지 | 마지막 클릭만 처리 |
| 폼 자동 저장 | 입력이 멈춘 후 저장 요청 |
JavaScript 구현
기본 구현
function debounce(fn, delay) {
let timer = null;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// 사용 예: 검색 입력
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', debounce((e) => {
fetchSearchResults(e.target.value); // 300ms 동안 입력이 없으면 실행
}, 300));
React 예시
import { useState, useCallback } from 'react';
function SearchBar() {
const [results, setResults] = useState([]);
const fetchResults = useCallback(
debounce(async (query) => {
const res = await fetch(`/api/search?q=${query}`);
setResults(await res.json());
}, 300),
[]
);
return (
<input
placeholder="검색어 입력"
onChange={(e) => fetchResults(e.target.value)}
/>
);
}
디바운스 vs 쓰로틀
| 항목 | 디바운스 (Debounce) | 쓰로틀 (Throttle) |
|---|---|---|
| 실행 시점 | 마지막 이벤트 이후 대기 시간 경과 시 | 일정 간격마다 한 번씩 |
| 실행 횟수 | 연속 이벤트 중 1번 | 간격마다 주기적 |
| 적합한 경우 | 검색 입력, 폼 저장 | 스크롤 이벤트, 무한 스크롤 |
이벤트: ● ● ● ● ● ● ● ● ●
| |
디바운스: ○ (1회) ○ (1회)
쓰로틀: ○ ○ ○ ○ ○ (주기적)
lodash 활용
실무에서는 직접 구현보다 검증된 라이브러리를 사용하는 경우가 많습니다.
import { debounce } from 'lodash';
// leading: true → 첫 이벤트에 즉시 실행, 이후 대기
const handleClick = debounce(submitForm, 500, { leading: true, trailing: false });
// trailing: true (기본값) → 마지막 이벤트 이후 실행
const handleInput = debounce(fetchResults, 300, { trailing: true });
실무 팁: 검색 자동완성에는 보통 200~500ms 정도의 대기 시간을 설정하며, 사용자 경험(UX)과 서버 부하 사이에서 적절한 값을 찾는 것이 중요합니다.