throttle과 debounce

devAnderson·2021년 12월 31일
0

TIL

목록 보기
16/106

이벤트 처리에 있어서 만약 스크롤을 했을 떄에 모든 스크롤의 움직임에 대하여 이벤트가 걸린다면 웹의 부하가 막중할 뿐더러 그 이벤트마다 서버에 요청을 보낸다면 서버에도 영향을 준다. 따라서 해당 이벤트를 적절하게 처리하는 방법이 필요한데, 그 방법중 2가지가 스로틀링과 디바운스다


debounce

디바운스는 간단하게 말하자면 비동기적인 호출을 매 이벤트마다 실행하되, 만약 기존에 이미 비동기 호출이 존재한다면 그 호출을 취소하고 다시금 호출을 하는 방식이다.

간이적인 방식으로 구현하자면

function debounce(callback, delay) {
  let timerId;

  return (e) => {
    if (timerId) clearTimeOut(timerId);
    timerId = setTimeOut(callback, delay);
  };
}

button.addEventListner(
  "click",
  debounce(() => {}, 500)
);

이와같이, 어떤 행동에 대해서 만약 타이머 아이디가 이미 설정되었을 경우, 해당 타이머 아이디를 이용하여 등록되어있던 타임아웃을 삭제하고 새롭게 등록하는 형태로 되어있다.
이게 가능한 이유는 addEventListner에서 등록되는 함수가 debounce가 호출되면서 timerId를 렉시컬 환경으로 인지한 상태로 클로져를 리턴하기 때문이다. 즉, 이벤트 리스너로 등록되는 함수를 계속해서 실행하면 실행 컨텍스트에 있는 값에 따라 계속 기존의 아이디로 타이머를 지우고 새로 등록할 수 있는 것이다.

해당 방식을 통해서 만약 사용자가 input을 계속 넣다가 넣는게 일정시간이 끝나면 자동으로 그것에 대해서 결과물을 보여주는 자동완성과 같은 행동을 만들 때에 도입하면 좋다


throttle

쓰로틀은 디바운스와는 다르게, 특정 비동기적 함수의 실행을 하나의 단위로 보고 그 실행단위가 끝나기 전까지는 동일한 요청은 전부 무시하는 형태로 만들어져 있는 구조다
예를 들어보자

function throttle(callback, delay) {
  let timerId;

  return (e) => {
    if (timerId) return;
    setTimeOut(callback, delay);
    timerId = null;
  };
}

button.addEventListner(
  "click",
  throttle(() => {}, 500)
);

디바운스떄와 다르게, 만약 어떠한 행위를 실행한다면 그 비동기적인 행위가 인식되면서 아이디를 리턴한다. 그리고 나서 동일한 요청이 계속되면, timerId를 보고 이미 동일한 요청이 있으므로 전부 return으로 무시하고, 그것이 끝나고 나면 비로소 새로운 비동기적 요청을 실행하는 형태로 되어있다.

이러한 방식을 쓰기에 가장 좋은 것은 스크롤 이벤트이다. 스크롤 이벤트와 같은 경우, 동일한 mouseMove라는 이벤트가 수도없이 발생하는데, 그것을 다 인지하기보다 단 한번만의 움직임으로 모두 뭉퉁거렸다가 그 움직임이 끝나면 새롭게 다시 인식하는 방식으로 구현할 수 있다.

실제로는 저렇게 쓰기보다 lodash에 있는 쓰로틀과 디바운스 함수를 사용하는 것이 더 안전하고 범용성이 좋다.

profile
자라나라 프론트엔드 개발새싹!

0개의 댓글