Debounce와 Throttle

Debounce와 Throttle은 이벤트나 함수 호출의 빈도를 줄여서 성능을 최적화 시키기 위해 사용되는 개념들이다.

검색하는 상황을 예시로 들어보자.

한 글자 입력시 마다 요청을 보내는 것보다, 입력 중간중간 특정 시점이나 입력이 끝난 후 요청을 보낸다면 api 호출의 수가 줄어들게 된다.

이 때, Throttle은 특정 시점에 api를 호출하는 것이고 Debounce는 입력이 끝난 후에 api를 호출하는 것이다.


👀 Debounce

연이어 발생한 이벤트를 하나의 그룹으로 묶어서 처리하는 방식이다.

주로 처음이나 마지막으로 실행된 함수를 처리하는 방식으로 사용한다.

 

요청이 들어오고 일정 시간이 지난 후에 요청을 수행한다.

일정 시간 안에 같은 요청이 추가로 들어오면 이전 요청은 취소된다.

 

이벤트를 실행하는 기점으로 Leading Edge와 Trailing Edge로 나뉜다.

leading 처음 실행하는 함수를 처리하는 것이고, trailing 가장 마지막에 실행하는 함수를 처리하는 것이다.

 

코드로 보는게 더 이해가 잘 될 것 같아서 코드를 가져왔다.

const $input = document.querySelector("#input");
const $app = document.querySelector("#app");

const callAjaxRequest = (e) => {
  $app.insertAdjacentHTML("beforeend", `<p>ajax 요청: ${e.target.value}</p>`);
};

const debounce = (func, wait, leading = false) => { 	// false-> trailing
  let timer; 
  return (e) => {
    let callNow = leading && !timer; 

    const later = () => {
      timer = null;
      if (!leading) {
        func(e);
      }
    };

    clearTimeout(timer);
    timer = setTimeout(later, wait);

    if (callNow) {
      func(e);
    }
  };
};

$input.addEventListener("input", debounce(callAjaxRequest, 1000, true));

 

- Leading Edge

leading이 true이기 때문에 callNow의 값은 timer 값에 의해 정해진다.

첫 실행 시에는 timer에 값이 없기 때문에 callNow에는 true가 할당되고 timer를 설정해준다.

callNow의 값이 true이기 때문에 바로 콜백함수를 실행시킨다.

다음 실행부터는 timer가 존재하기 때문에 callNow에는 false가 할당되고

timer를 재설정하고 콜백함수는 실행되지 않는다.

 

- Trailing Edge

leading이 false이기 때문에 callNow에는 false가 할당된다.

첫 실행 시, timer를 설정해준다.

다음 실행부터는 계속해서 setTimeout을 통해 timer를 초기화 시켜준다.

이 때까지 콜백함수는 한 번도 실행되지 않았다.

만약 timer 시간동안 사용자의 입력이 없다면 그 때 콜백함수를 실행해서 요청을 보낸다.

 

 

- 사용예시

컴포넌트 리사이징 같이 마지막 동작에 대한 처리가 중요한 경우에 사용한다.

ex) 사용자가 창 크기 조정을 멈출 때까지 기다렸다가 resizing event 반영

 

참고로 Debounce하면 보통 Trailing Edge 방식으로 동작한다고 생각한다 !


👀 Throttle

이벤트를 일정주기마다 발생하도록 하는 방식이다.

만약 throttle의 설정 시간으로 100ms를 준다면, 해당 이벤트는 100ms 동안 최대 한 번만 발생한다.

 

즉, 일정 시간 동안 요청이 한 번만 수행되도록 한다.

const throttle = (func) => {
  let timer;

  return () => {
    if (!timer) {
      timer = setTimeout(() => {
        timer = null;
        func();
      }, 50);
    }
  };
};

$app.addEventListener("scroll", throttle(increaseCountNumber));

Throttle의 동작방식은 간단하다.

타이머를 설정하고 타이머로 설정된 시간이 지나면 콜백함수를 실행한다.

 

- 사용예시

처리량은 조절하면서 서비스의 연속성도 유지해야할 때 사용된다.

ex) 자동완성, 무한스크롤 기능에 사용


👀 Debounce Leading Edge와 Throttle 차이

첫 요청이 들어오고 일정 시간 동안 모든 요청을 무시한다는 점에서 비슷하다.

 

Debounce leading edge는 설정한 타이머 시간안에 들어오는 모든 요청을 무시하지만,

Throttle은 지속적인 요청이 들어오면 정해진 타이머 시간이 지난 후 요청을 허용한다.


👀 Debounce와 Throttle 차이

Debounce는 주로 불필요한 api 호출을 막기 위해서 사용되고,

Throttle은 성능최적화에 주로 사용된다.

 

Debounce는 특정 시간동안 요청을 계속 무시하지만

Throttle은 특정 시간이 지나면 무조건 한 번은 실행되기 때문이다.

 

만약 자동완성 무한 스크롤 기능에 Debounce를 쓴다면 스크롤이 멈추는 등의 문제가 생길 수 있다.


👀 Lodash

Javascript 라이브러리 중 하나이다.

데이터의 구조나 객체 들의 값을 핸들링 할 때 유용하게 사용할 수 있다.

물론 debounce와 throttle 함수도 있다!

 

_.debounce(func, wait, options)

func = 실행할 함수

wait = 타이머

options = true이면 leading edge, false이면 trailing edge로 동작한다.

 

_.throttle(func, wait)

func = 실행할 함수

wait = 타이머

 

다 구현되어 있으니 간편하게 가져다 쓰면 되겠다 🙂

'WEB' 카테고리의 다른 글

SEO 최적화  (0) 2024.08.20
webpack vs vite  (0) 2024.08.14
이벤트 전파와 이벤트 위임  (0) 2024.08.02
웹 레이아웃  (0) 2024.07.31
Border vs Outline  (0) 2024.07.31