logo
Throttling과 Debouncing

Throttling과 Debouncing

Throttling

Throttling은 일정 시간(window) 동안 함수 호출을 최대 1번만 실행되도록 제한할 때 유용하다.

가장 흔한 예시는 scroll 이벤트다. 사용자가 스크롤을 한 번 쭉 내리기만 해도 이벤트가 짧은 시간에 수십~수백 번 발생할 수 있다. 이때 이벤트가 발생할 때마다 핸들러를 그대로 실행하면 다음 문제가 생기기 쉽다.

  1. 핸들러 연산이 무거우면 렌더링이 밀리면서 프리징(버벅임) 이 발생할 수 있고
  2. 이벤트마다 서버 요청을 보내면 불필요한 API 호출이 폭증할 수 있다

그래서 스크롤/리사이즈처럼 “자주 발생하는 이벤트”에는 throttling이 좋은 안전장치가 된다.

참고: lodash의 throttle은 leading/trailing 같은 옵션까지 지원해 더 유연하지만, 핵심 아이디어는 비슷하다.

간단 구현 (Closure 기반)

function throttle(func, delay) {
    let throttling = false;

    return function() {
        if (!throttling) {
            throttling = true;
            setTimeout(() => {
                func.apply(this, arguments);
                throttling = false;
            }, delay);
        }
    };
}

mydiv.addEventListener("scroll", throttle(() => {console.log("Heavy Task...")}, 1000));

Debouncing

Debouncing도 중복 호출을 줄인다는 점에서는 throttling과 같지만, 동작 방식이 다르다.

  • Throttling: “2초 동안 최대 1번”처럼 주기적으로 실행을 허용 
  • Debouncing: 호출이 계속 들어오면 실행을 계속 미루다가, 마지막 호출 이후 delay가 지나면 1번만 실행

이 “미루기” 특성 때문에 debouncing은 보통 input 이벤트에서 많이 쓴다. 사용자가 타이핑할 때마다 검색 API를 호출하는 대신, 타이핑이 잠깐 멈춘 뒤(예: 500ms) 한 번만 요청하면 트래픽도 줄고 UX도 더 자연스럽다. 

간단 구현 (closure 기반)

function debounce(func, delay) {
    let timeoutId;
    return function() {
        clearTimeout(timeoutId);
        timeoutId = setTimeout(() => {
            func.apply(this, arguments);
        }, delay);
    };
}

inputField.addEventListener('input', debounce(saveData, 500));

Written on

2024-09-01 06:35

Comments