디바운스

연속으로 발생하는 이벤트를 그룹화하여, 마지막 이벤트 이후 일정 시간이 지나야 한 번만 실행되도록 제어하는 기법입니다.

동작 원리

이벤트 발생 타임라인 (대기 시간: 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)과 서버 부하 사이에서 적절한 값을 찾는 것이 중요합니다.

CSLOG에서 보기