DYO 공부하는 블로그

[JS] 이벤트 최적화, 디바운스와 스로틀 본문

JS

[JS] 이벤트 최적화, 디바운스와 스로틀

DYODa 2025. 6. 13. 23:00

디바운스(debounce)와 스로틀(throttle)은 고빈도 이벤트를 제어하기 위한 대표적인 퍼포먼스 최적화 기법이다. resize, mouse 이동 관련한 이벤트(호출 빈도가 정말 많은 이벤트) 들을 관리하기 위해 사용한다.

 

1. 디바운스

이벤트가 연속해서 발생하는 경우, 일정 시간 기다렸다가 한 번만 실행하도록 한다. 마지막으로 수행한 이벤트만 실행됨.

 

- 작동 원리

이벤트가 발생할 대마다 타이머를 초기화한다. 일정 시간 동안 추가 이벤트가 없으면 콜백을 실행한다.

 

- 실제 사용 예시

ground.addEventListener("mousemove", debounce(handleMove, 1000));

// 디바운스
function debounce(f, limit = 1000) {
  let timeout;

  return function(e) {
    clearTimeou(timeout);
    setTimeout(() => {
      f.call(this, e);
    }, limit);
  };
}

mousemove 이벤트는 호출 주기가 너무 짧다. 그래서 디바운스를 이용해 호출 주기를 늘릴 수 있다. 이벤트가 실행될 때마다 이전에 수행된 timeout을 초기화하며 callback에 timeout 변수를 캡슐화하고 return으로 function을 담아 callback으로 addeventListener에 넣는다.

 

콜백에서 이벤트 관리하는 게 어려운 경향이 있는데,

ground.addEventListener("mousemove", debounce(handleMove, function (e) {
    clearTimeou(timeout);
    setTimeout(() => {
      f.call(this, e);
    }, limit);
  };));

실제 실행 단계에서는 이런 상태가 되는 것이다. 따라서 e파라미터도 전달이 가능하고, this 파라미터도 call을 이용해 전달이 가능하다.

 

2. 스로틀

지정한 시간 간격마다 한 번만 실행되도록 하는 방식이다. 즉, 주기적으로 콜백이 실행되도록 하는 방식이다. 수도꼭지를 약하게 틀어놓듯이, 조금씩 흘러나오게 하는 설계이다.

 

- 작동 원리

일정 간격 동안은 추가 이벤트를 무시하고, 이벤트마다 타이머 후에만 다시 실행된다.

//쓰로틀
function throttle(f, limit = 200) {
  let wait = false;

  return (...args) => {
    if (!wait) {
      f.apply(this, args);
      wait = true;
      setTimeout(() => (wait = false), limit);
    }
  };
}

실행 단계 구조는 디바운스와 같다. apply를 이용해 args로 이벤트 객체를 콜백 함수에 던져줄 수도 있다. settimeout으로 wait상태를 교체하면 주기적으로 이벤트가 발생하여 콜백을 수행하는 구조이다.

 

3. 쓰로틀, 디바운스로 수행되는 콜백이 짧더라도 성능 향상이 이루어지는 이유

쓰로틀, 디바운스를 수행하더라도 비교 연산이나 이벤트 관리는 계속해서 수행된다. 단순 연산이 남아있더라도, 실제 callback 실행 횟수를 줄이는 것 자체가 브라우저 부담을 대폭 줄이기 때문이다.