본문 바로가기
매일 해내는 개발/Develog

[Develog] Throttling & Debouncing

by 해야지 2023. 1. 31.
반응형

Throttling

개념: 짧은 시간 간격으로 연속해서 발생한 이벤트들을 일정시간 단위(delay)로 그룹화하여 처음 또는 마지막 이벤트 핸들러만 호출되도록 하는 것

예) 무한스크롤

Type1 Leading Edge

처음 이벤트 핸들러만 호출

// Leading Edge Throttling
  const throttle: ControlDelay = (delay) => {
    if (timerId) {
      // timerId가 있으면 바로 함수 종료
      return;
    }
    console.log(`API요청 실행! ${delay}ms 동안 추가요청 안받음`);
    timerId = setTimeout(() => {
      console.log(`${delay}ms 지남 추가요청 받음`);
      // alert("Home / 쓰로틀링 쪽 API호출!");
      timerId = null;
    }, delay);
  };

Type2 Trailing Edge

마지막 이벤트 핸들러만 호출

Type3 Leading & Trailing Edge

처음과 마지막 이벤트 핸들러만 호출

Debouncing

개념

전기 회로에서 나온 용어로, 스위치를 눌렀을 때 짧은 시간 간격으로 on off가 반복되는 bouncing 현상을 없애는 행위

프로그래밍 세계에서의 debouncing

짧은 시간 간격으로 연속해서 이벤트가 발생하면 이벤트 핸들러를 호출하지 않다가 마지막 이벤트로부터 일정 시간(delay)이 경과한 후에 한 번만 호출하도록 하는 것

예) 입력값 실시간 검색, 화면 resize 이벤트

// Trailing Edge Debouncing
  const debounce: ControlDelay = (delay) => {
    if (timerId) {
      // 할당되어 있는 timerId에 해당하는 타이머 제거
      clearTimeout(timerId);
    }
    timerId = setTimeout(() => {
      // timerId에 새로운 타이머 할당
      console.log(`마지막 요청으로부터 ${delay}ms지났으므로 API요청 실행!`);
      timerId = null;
    }, delay);
  }; 

 

메모리 누수(Memory Leak)

: 필요하지 않은 메모리를 계속 정유하고 있는 현상

 💡 (Q&A) setTimeout 이 메모리 누수(Memory Leak)를 유발하는 지?

상황에 따라 메모리 누수를 일으킬 수도 있고 아닐 수도 있습니다.

하나의 페이지에서 페이지 이동 없이 setTimeout을 동작시키고 타이머 함수가 종료될 때까지 기다린다면 메모리 누수는 없습니다.

리액트로 만든 SPA 웹사이트는 페이지 이동 시 컴포넌트가 언마운트 됩니다.

그런데 페이지 이동 전에 setTimeout 으로 인해 타이머가 동작중인 상태에서 clearTimeout을 안해주고 페이지 이동 시 컴포넌트는 언마운트 되었음에도 불구하고 타이머는 여전히 메모리를 차지하고 동작하고 있습니다. 이 경우 메모리 누수(Memory Leak)에 해당한다고 말할 수 있습니다.

 

이를 해결 하기 위해 unMount 될 때타이머를 지워주면 된다.

useEffect(() => {
    return () => {
      // 페이지 이동 시 실행
      if (timerId) {
        // 메모리 누수 방지
        clearTimeout(timerId);
      }
    };
  }, [timerId]);

그런데 위 코드는 개념 확인용으로 실전에서 쓸 수 없다!

그 이유는 실전에서는 re-redering을 해야하기 때문이다.(state or props 변경)

Throttling 코드에 state 변경 코드를 넣게 되면

// Leading Edge Throttling
  const throttle: ControlDelay = (delay) => {
    if (timerId) {
      // timerId가 있으면 바로 함수 종료
      return;
    }
   setState(!state)// re-rendering 발생
    console.log(`API요청 실행! ${delay}ms 동안 추가요청 안받음`);
    timerId = setTimeout(() => {
      console.log(`${delay}ms 지남 추가요청 받음`);
      // alert("Home / 쓰로틀링 쪽 API호출!");
      timerId = null;
    }, delay);
  };

throttling이 전혀 적용이 안되는 걸 볼 수 있다.(delay 적용 x)

그렇다면!

React에서 어떻게 Throttling, Debouncing을 적용할 수 있을까?

Lodash에서 제공하는 메소드 사용

throttle

 

Lodash Documentation

_(value) source Creates a lodash object which wraps value to enable implicit method chain sequences. Methods that operate on and return arrays, collections, and functions can be chained together. Methods that retrieve a single value or may return a primiti

lodash.com

debounce

 

Lodash Documentation

_(value) source Creates a lodash object which wraps value to enable implicit method chain sequences. Methods that operate on and return arrays, collections, and functions can be chained together. Methods that retrieve a single value or may return a primiti

lodash.com

 

반응형

댓글