본문 바로가기
Developer/JavaScript

JavaScript Debounce(디바운스), Throttle(스로틀) 이란? (구현 방법 포함)

by 김씩씩 2022. 12. 16.

JavaScript Debounce(디바운스), Throttle(스로틀) 이란? (구현 방법 포함)


서비스를 만들어가면서 프론트엔드 작업을 하게 되면 사용자들과의 상호작용을 위해 JavaScript로 다양한 이벤트에서 다양한 동작이 이루어지는 작업을 하게 됩니다.
가령 특정 검색어를 입력하는 Input에서 검색어를 입력했을 때 자동완성 또는 연관검색어를 보여줄 때, 스크롤을 하는 과정에서 특정 동작을 하고 싶을 때 등 다양한 이벤트에 따라 다양한 기능을 사용자분들에게 제공할텐데요.

만약,

  1. 특정 검색어를 입력하는 Input에서 검색어를 입력했을 때 자동완성 또는 연관검색어를 보여주는 기능을 만들고 있는데 keydown 이벤트로 입력할 때 마다 자동완성 또는 연관검색어를 찾아주는 것이 아니라 어느정도 입력이 되었을 때 보여주고 싶다면?
  2. 스크롤이 될 때 마다 특정 함수를 계속 실행시켜서 너무 많은 동작으로 인해 화면이 느려지는 현상이 발생해 일정 간격을 두고 해당 기능이 작동하게 하고싶다면?


이럴 때 사용할 수 있는 것이 바로 Debounce(디바운스)Throttle(스로틀) 입니다.

먼저 Debounce와 Throttle이 무엇인지 간단하게 말씀드려보자면,

  • Debounce(디바운스): 같은 이벤트가 반복되게 발생하는 경우 반복적으로 발생하던 이벤트가 일정 시간동안 다시 발생하지 않으면(즉, 반복적으로 발생하던 이벤트가 끝나면) 콜백 함수를 실행되도록 하는 것.
  • Throttle(쓰로틀): 같은 이벤트가 반복되게 발생하는 경우 일정 시간 간격으로 콜백 함수를 실행되도록 하는 것. (즉, 한번 콜백 함수가 한번 실행되면 같은 이벤트가 발생되더라도 일정 시간동안은 해당 콜백함수를 실행시키지 않게 해주는 것)

이렇게 정리할 수 있을 것 같습니다!

즉 앞서 말씀 드린 만약의 상황 1번에서는 디바운스를 사용하고 상황 2번에서는 스로틀을 사용하는 것으로 문제를 해결할 수 있을 것 입니다!

디바운스와 스로틀은 라이브러리를 통해 사용할 수 있지만 이해를 돕고 조금 더 자세한 설명을 위해 JavaScript로 구현한 코드를 보여드리면서 설명드리도록 하겠습니다.
디바운스와 스로틀은 Closure(클로저)의 개념을 이해하신다면 간단하게 구현해볼 수 있습니다!
그럼 사용 예시, 그리고 JavaScript로 해당 기능을 구현한 코드와 함께 더 자세하게 설명드리도록 하겠습니다.

Debounce(디바운스)

const debounce = (callback, delay) => {
  let timer;
  return function () {
    clearTimeout(timer);
    timer = setTimeout(_ => callback.apply(this, arguments), delay);
  };
};

JavaScript로 구현한 Debounce입니다.
코드를 보시면 아시겠지만 클로저를 사용하여 구현할 수 있습니다!

callback은 이벤트가 발생했을 때 실행될 콜백 함수이며 delay는 말그대로 콜백 함수를 실행시킬 딜레이 시간입니다. setTimeout에 사용할 것이기 때문에 millisecond 단위로 입력해서 사용합니다.
반환할 함수 밖에 setTimeout을 사용해 타이머로 사용할 변수 timer를 만들어둡니다.
반환할 함수 내에서 timer 변수에 setTimeout()을 사용하면서 설정하는 delay 시간 뒤에 내부 함수가 실행되도록 합니다.
setTimeout()을 하기 전에 clearTimeout(timer) 을 하는 것으로 만약 delay로 설정한 시간보다 빠른 시간에 같은 이벤트가 발생했을 때 앞선 이벤트는 삭제시켜버리는 것으로 디바운스가 이루어집니다!
setTimeout() 내부에서는 실행될 콜백함수에 apply를 사용하여 this를 바인딩해주고 arguments를 함께 넘겨주는 것으로 콜백함수를 실행시켜 줍니다.

※ 짧은 참고사항으로 return에서 함수표현식이 아닌 함수선언식을 사용하는 이유는 this가 이벤트를 등록한 엘리먼트이기 위해서이며 (함수표현식을 사용했다면 window가 this 입니다!), 함수선언식에서 기본적으로 가지고 있는 전달받는 모든 인수를 가지고 있는 배열 형태의 arguments 라는 속성을 사용하기 위함입니다.
그에 반해 setTimeout 내에서는 함수표현식을 사용하는 이유는 그 반대겠죠? this와 arguments를 반환하는 함수의 this와 arguments를 사용하기 위함입니다!

위 코드를 사용하는 예시를 한번 만들어 보겠습니다!

<div>
  <input id="input" type="text">
  <p id="text"></p>
</div>

<script>
  const debounce = (callback, delay) => {
    let timer;
    return function () {
      clearTimeout(timer);
      timer = setTimeout(_ => callback.apply(this, arguments), delay);
    };
  };

  const action = function (e) {
    document.querySelector('#text').innerHTML = this.value;
  };

  document.querySelector('#input').addEventListener('keydown', debounce(action, 1000));
</script>

 

Input에 글을 입력하면 그 바로 아래에 입력한 글이 그대로 보여지는 간단한 예시입니다.
위와 같이 글을 입력하다가 멈추고 난 후, 더이상 입력을 하지 않고 설정한 1000 millisecond (1초) 가 지나야 action 함수의 동작이 실행됩니다.
글을 입력하다가 더이상 입력하지 않고 1초가 지난 뒤 입력한 글이 아래에 업데이트 되는 것을 확인하실 수 있습니다!

Throttle(스로틀)

const throttle = (callback, delay) => {
  let timer;
  return function () {
    if (!timer) {
      timer = setTimeout(_ => {
        callback.apply(this, arguments);
        timer = undefined;
      }, delay);
    }
  };
};

JavaScript로 구현한 Throttle입니다.
이 역시도 코드를 보시면 아시겠지만 클로저를 사용하여 구현할 수 있습니다!

callback은 이벤트가 발생했을 때 실행될 콜백 함수이며 delay는 말그대로 콜백 함수를 실행시킬 딜레이 시간입니다. setTimeout에 사용할 것이기 때문에 millisecond 단위로 입력해서 사용합니다.
반환할 함수 밖에 setTimeout을 사용해 타이머로 사용할 변수 timer를 만들어둡니다.
여기까지 디바운스를 구현할 때와 같고 이제 반환할 함수 내부의 구현이 다릅니다!
timer 변수가 undefined 상태라면 timer 변수에 setTimeout()을 사용하면서 설정하는 delay 시간 뒤에 내부 함수가 실행되도록 합니다.
setTimeout() 내부에서는 실행될 콜백함수에 apply를 사용하여 this를 바인딩해주고 arguments를 함께 넘겨주는 것으로 콜백함수를 실행시켜 주고, timer를 undefined로 만들어버립니다.
delay로 설정한 시간까지 timer 변수는 undefined 상태가 아닐 것이므로 만약 delay로 설정한 시간보다 빠른 시간에 같은 이벤트가 발생했을 때 if(!timer) 에서 걸러져 내부가 실행되지 않는 것으로 스로틀이 이루어집니다!

위 코드를 사용하는 예시를 한번 만들어 보겠습니다!

<div>
  <input id="input" type="text">
  <p id="text"></p>
</div>

<script>
  const throttle = (callback, delay) => {
    let timer;
    return function () {
      if (!timer) {
        timer = setTimeout(_ => {
          callback.apply(this, arguments);
          timer = undefined;
        }, delay);
      }
    };
  };


  const action = function (e) {
    document.querySelector('#text').innerHTML = this.value;
  };

  document.querySelector('#input').addEventListener('keydown', throttle(action, 1000));
</script>

 

Debounce 설명에서 보여드렸던 것과 같이 Input에 글을 입력하면 그 바로 아래에 입력한 글이 그대로 보여지는 간단한 예시입니다.
위와 같이 글을 계속 입력을 하면 설정한 1000 millisecond (1초) 간격으로 action 함수의 동작이 실행되는 것을 확인하실 수 있습니다!
Debounce 때와는 또 다르게 글을 입력하고 있는 와중에도 1초 간격으로 입력한 글자가 나타내지는 것을 확인하실 수 있습니다!


이상으로 Debounce(디바운스), Throttle(스로틀)에 대한 설명과 JavaScript로 구현해보는 방법에 대한 설명을 마치도록 하겠습니다.


도움이 되셨다면 공감, 댓글 부탁드립니다!
궁금하신 점이나 요청사항은 언제든지 말씀해주세요!
피드백도 언제나 환영입니다!

감사합니다.


댓글