디바운싱과 쓰로틀링

juyeong-s·2022년 8월 27일
2

자바스크립트

목록 보기
1/1
post-thumbnail

잘못된 내용이 있다면 댓글로 알려주세요 ! 😄😊

디바운싱과 쓰로틀링은 디바이스에 무리를 주지 않기 위해 사용하는 프로그래밍 기법이다. 일종의 최적화라고 보면된다. 그렇다면 각각의 의미를 알아보자.

  • 디바운싱(debouncing) : 연이어 발생한 이벤트를 하나의 그룹으로 묶어서 처리하는 방식이다. 주로, 그룹에서 처음이나 마지막으로 실행된 함수를 처리하는 방식으로 사용된다.
  • 쓰로틀링(throttling) : 연이어 발생한 이벤트에 대해, 일정한 delay를 포함시켜 연속적으로 발생한 이벤트는 무시하는 방식을 뜻한다. 즉, delay시간동안 호출된 함수는 무시하는 방식이다.

디바운싱

예시를 들어 쉽게 설명해보겠다. 식당에서 주문을 할 때,

첫번째 방법

1. 고객: 콜라 주문이요!
2. 직원: 콜라 주문넣기
3. 고객: 파스타 주문이요!
4. 직원: 파스타 주문넣기
5. 고객: 스테이크 주문이요!
6. 직원: 스테이크 주문넣기

두번째 방법

1. 고객: 콜라, 파스타, 스테이크 주문이요!
2. 직원: 콜라, 파스타, 스테이크 주문넣기

당연히 두번째 방법이 훨씬 효율적이다. 이렇게 주문이 끝날 때까지 듣고 있다가 마지막 요청이 완료된 후 주문을 넣는 것이 디바운싱의 원리이다.

디바운싱 사용예시

스크롤 이벤트로 예시를 들어보겠다. 먼저 디바운싱 기법을 사용하지 않았을 때 예시를 보자.

디바운싱 적용 X 코드

<!DOCTYPE html>
<html>
  <body>
    <div id="main" style="height: 300vh">
      <div style="position: fixed">
        <h3>아무 처리도 하지 않았을 경우</h3>
        <div>
          <label>이벤트 발생 : </label>
          <span id="count">0</span>
        </div>
      </div>
    </div>
  </body>
  <script>
    window.addEventListener("scroll", function (e) {
      console.log("스크롤 이벤트 발생");
      const count = document.getElementById("count");
      count.innerText = parseInt(count.innerText) + 1;
    });
  </script>
</html>

1

스크롤 이벤트가 발생하는 모든 순간마다 함수가 호출되고 count가 계속 늘어나게 된다. 만약 이 함수가 좀 더 무거운 작업을 하게 된다면 스크롤을 할 때마다 렌더링이 되고 성능 이슈로 이어질 수 있다. 그렇다면 디바운싱 기법을 적용한 코드를 보자.

디바운싱 적용 O 코드

<!DOCTYPE html>
<html>
  <body>
    <div id="main" style="height: 300vh">
      <div style="position: fixed">
        <h3>Debouncing 적용</h3>
        <div>
          <label>이벤트 발생 : </label>
          <span id="count">0</span>
        </div>
      </div>
    </div>
  </body>
  <script>
    let debouncer;
    window.addEventListener("scroll", function (e) {
      if (debouncer) {
        clearTimeout(debouncer);
      }

      debouncer = setTimeout(function () {
        console.log("스크롤 이벤트 발생");
        const count = document.getElementById("count");
        count.innerText = parseInt(count.innerText) + 1;
      }, 300);
    });
  </script>
</html>

2

debouncer라는 변수에 delay 300ms를 걸어준 setTimeout 함수를 대입한다. 여기에 클로저 개념이 쓰였다고 볼 수 있다. 만약 현재 발생한 스크롤 이벤트가 이전에 발생한 스크롤 이벤트보다 300ms내에(보다 빨리) 발생했다면, 이전 이벤트에 기록된 setTimeout이 대입된 debouncer에 다시 새로운 setTimeout을 대입시킨다. 이때 debouncer에 값이 들어있다면 clearTimeout으로 해당 타이머를 취소해야 한다. 그래야 이전 타이머가 지워지고 새로운 타이머가 대입된다. 
결과적으로 마지막으로 발생한 이벤트에 대해서만 300ms가 지난 후 setTimeout안의 로직이 수행되어 카운트가 적절히 변하게 되는 것이다.

쓰로틀링

쓰로틀링은 보통 성능 문제 때문에 많이 사용하게 된다. 쓰로틀링은 실행 횟수에 제한을 거는 것이라고 보면 된다.
스크롤 이벤트가 발생할 때마다 이벤트가 발생하지 않고, 몇 초에 한 번 또는 몇 밀리초에 한 번씩만 실행되도록 제한을 두는 것이다.

쓰로틀링 적용 O 코드

<!DOCTYPE html>
<html>
  <body>
    <div id="main" style="height: 300vh">
      <div style="position: fixed">
        <h3>Throttling 적용</h3>
        <div>
          <label>이벤트 발생 : </label>
          <span id="count">0</span>
        </div>
      </div>
    </div>
  </body>
  <script>
    let throttler;
    window.addEventListener("scroll", function (e) {
      if (throttler) {
        return;
      }
      throttler = setTimeout(function () {
        console.log("스크롤 이벤트 발생");
        const count = document.getElementById("count");
        count.innerText = parseInt(count.innerText) + 1;
        throttler = null;
      }, 200);
    });
  </script>
</html>

실행 결과, 스크롤을 천천히 움직여도, 엄청 빠르게 움직여도 일정하게 count가 변하는 것을 볼 수 있다.

여기서 디바운스와 다른 점은 throttler에 타이머가 설정되어 있을 경우 clearTimeout으로 타이머를 취소해주는 것이 아닌 return으로 그냥 종료 시키는 것이다. 그렇게 되면 이전에 대입되었던 타이머가 취소되지 않고, 타이머가 설정이 된 이후로부터 300ms내에 실행되게 될 것이다. throttler에 타이머가 설정되고 난 후 300ms동안은 throttler가 이벤트를 쥐고 있는 것이다. 이벤트를 쥐고 있는 300ms동안 1번의 이벤트만 발생하게 된다.
또한, 로직이 실행되고 난 후 throttler를 null로 초기화 시켜주면서 throttler에 값이 없다는 것 알려주어야 다음 스크롤 이벤트 발생 시 return 되지 않고 setTimeout을 다시 걸어줄 수 있을 것이다.

콘솔로 확인해보니 setTimeout이 양의 정수값을 리턴하는데, 300ms후 로직이 전부 끝나고 나서는 1을 출력하는 것을 확인했다. 우리는 clearTimeout으로 타이머를 초기화시켜주지 않았으므로 null로 값이 없다는 것을 알려주어야 한다.


레퍼런스

https://developer.mozilla.org/ko/docs/Web/API/setTimeout
https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout
https://velog.io/@yujuck/Javascript-%EB%94%94%EB%B0%94%EC%9A%B4%EC%8A%A4%EC%99%80-%EC%93%B0%EB%A1%9C%ED%8B%80%EB%A7%81
https://programming119.tistory.com/241

profile
frontend developer

0개의 댓글