ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Debounce와 Throttle
    카테고리 없음 2023. 6. 6. 23:06
    이 글은 2021.06.04에 타 플랫폼에 작성했던 글을 옮긴 포스트 입니다. 최신 정보와 불일치하는 정보가 있을수 있습니다.

     

    🤔 이게 뭐야?


    : 이벤트의 제어/제한을 위해 사용하는 기법

     

    아래 예제를 보자
    스크롤 이벤트가 발생할 때마다 콘솔을 찍어봤다

     

     

    단지 스크롤을 했을뿐인데 너무 많은 이벤트가 발생하는 것을 볼 수 있다.
    jQuery의 창시자 존 레식도 스크롤에 이벤트를 붙이는게 얼마나 나쁜지에 대한 글을 쓴 것이 있다(참고하려면 여기).

     

    이렇게 비정상적으로 많이 이벤트가 발생할 경우, 각 이벤트에 대한 콜백이 발생하고 이 콜백 함수의 비용도 어마어마 할 것이다.

     

    결국 성능 문제로 이어지고 사용자 경험을 낮추게 되기 때문에 적절하게 이벤트를 제한 해줄 필요가 있다.

     

    후! 왜 필요한지는 간단하게 알아보았고 이제 각각이 어떻게 다르고 어떤 상황에서 필요한지 알아보자

    1️⃣ debounce


    이벤트를 그룹화 해 특정 시간이 지난후 하나의 이벤트만 발생하도록 함
    연이어 발생하는 이벤트들 중 마지막 이벤트만 호출 된다

     

    아래는 Rx에서의 debounce 함수의 동작을 도식화 한 것이다.
    rx를 모르더라도 이벤트가 이렇게 발생하는구나~ 정도로만 보면 될 것 같다

     

    throttle과의 다른점이 위의 그림을 보면 보이는데 그룹화 된 이벤트 중 마지막 이벤트가 delay 되어 호출 된다

     

    🤔 어떤 경우에 쓰면 좋을까?

    • toggle 버튼의 이벤트 리스너
    • 검색 버튼이 없이 keyword의 현재 값에 따라 결괏 값을 불러오는 search page
    • 어뷰징이 발생할 수 있는 요소들에 사용하면 좋을것 같다(버튼, 토글, 스위치, ...)

     

    📝 코드

    const debounce = (fn, delay) => {
    	let timer = null;
      	
      	// timer에 접근 가능한 클로저 함수
    	return function(...args) {
          	// arguments로 변수 접근
    		const context = this;
    		timer && clearTimeout(timer); 
          		// 이벤트가 일어난 시점에 timer가 있으면 clear. 
          		//delay 동안 이벤트가 또 발생하지 않는다면 무사히 아래의 코드 실행
    		timer = setTimeout(() => {
    			fn.apply(context, args);
    		}, delay);
    	};
    };

     

    🤩 예제

    500ms 동안 이벤트가 발생하지 않는다면 이벤트를 실행 해주도록 함

     

     

    2️⃣ throttle


    이벤트를 일정 주기마다 발생
    지정 시간/간격 동안 발생하는 이벤트를 한 번만 실행 되도록 함

     

    실행 횟수를 제한함으로써 성능 문제 해결에 기여한다

     

    🤔 어떤 경우에 쓰면 좋을까?

    • 무한스크롤: 특정 스크롤 높이에 도달하면 새로운 데이터를 불러오도록 사용

     

    📝 코드

    이번에는 스크롤을 다 내렸을 때 스로틀을 구현해 보았다

    const throttle = (fn) => {
        return function(...args) {
          let context = this;
          if (
            document.documentElement.scrollTop +
              document.documentElement.clientHeight ===
            document.documentElement.scrollHeight
          ) {
            // 스크롤 되어 올라간 높이 + 보이는 만큼의 높이 === 스크롤 하지 않았을 때의 전체 높이
            fn.apply(context, args);
          }
        };
      }

    스크롤 높이에 사용된 값들이 더 궁금하다면 여기를 참조하자

     

    🤩 예제

    스크롤이 바닥에 닿을 때마다 이벤트가 실행됨을 볼 수 있다

     

    Lodash, Rx


    바닐라로 직접 구현해 보았지만, 사실 많이들 쓰고 간편하게 사용할 수 있는 방법이 있다.
    lodash 라이브러리에 내장된 debounce와 throttle를 쓰는것!

     

    직접 구현하기 싫다면 얘도 한번 고려해 보자(lodash repository)

     

    또 위의 표에서 예상했겠지만 rx에도 있으니 rx를 도입해 사용 중이라면 내장 함수를 사용하면 될 것 같다

     

    결론


    둘의 차이는 이벤트 발생 시점

    • Debounce: 이벤트 발생이 끝날때까지 무한적으로 기다림
    • Throttle: 이벤트 발생 이후 일정 주기마다 계속 실행

    위에서 상황을 나눠 봤지만 결국 작업의 성격에 따라 적용하면 된다.

    자동 완성을 예로 들었을 때,
    일정 주기로 자동으로 완성되는 리스트를 보여주는 경우
    사용자 측면에서는 throttle(검색 되는 경험)가 유리할 수 있지만,
    성능상 Debounce(1번만 호출)가 훨신 유리할 수 있다

    참고

Designed by Tistory.