자바스크립트에서 디바운스와 스로틀 구현하기

개념:

디바운스(debounce): 고주파 이벤트가 발생한 후 n초 동안 함수는 단 한 번만 실행됩니다. n초 내에 고주파 이벤트가 다시 발생하면 시간이 재설정됩니다.

스로틀(throttle): 고주파 이벤트가 발생하지만 n초 동안 함수는 단 한 번만 실행됩니다. 따라서 스로틀은 함수의 실행 빈도를 줄입니다.

디바운스와 스로틀 모두 함수의 실행 빈도를 제한하여, 과도한 트리거로 인해 발생할 수 있는 지연, 가짜 데드락 또는 프로그램 정지 현상을 방지하는 데 사용됩니다.

디바운스:

  • 구현 방법: 이벤트가 발생할 때마다 지연된 호출 메서드를 설정하고 이전의 지연된 호출을 취소합니다.
  • 단점: 지정된 시간 간격 내에 이벤트가 계속해서 트리거되면 호출이 지속적으로 지연될 수 있습니다.
/* 
  1. 디바운스: 이벤트가 발생할 때마다 지연된 호출을 설정하고 이전의 지연 호출을 취소합니다.
   단점: 지정된 시간 안에 이벤트가 계속해서 발생하면 호출이 지속적으로 지연됩니다.
*/
function debounce(fn, wait) {
  let timerId = null;
  
  return function (...args) {
    const context = this;

    if (timerId !== null) {
      clearTimeout(timerId);
    }

    timerId = setTimeout(() => {
      fn.apply(context, args);
    }, wait);
  };
}

// 예제 함수
function logRandom() {
  console.log('디바운스:', Math.random());
}

// 클릭 이벤트 처리
window.addEventListener('click', debounce(logRandom, 500));

스로틀:

  • 구현 방법: 타임스탬프와 타이머를 사용합니다.
// 타임스탬프 기반 스로틀
function throttleByTimestamp(fn, limit) {
  let lastCallTime = 0;

  return function (...args) {
    const now = Date.now();
    const context = this;

    if (now - lastCallTime >= limit) {
      fn.apply(context, args);
      lastCallTime = now;
    }
  };
}

// 타이머 기반 스로틀
function throttleByTimer(fn, limit) {
  let timeoutId = null;

  return function (...args) {
    const context = this;

    if (!timeoutId) {
      timeoutId = setTimeout(() => {
        fn.apply(context, args);
        timeoutId = null;
      }, limit);
    }
  };
}

// 타임스탬프와 타이머를 결합한 스로틀
function combinedThrottle(fn, limit) {
  let timeoutId = null;
  let lastExecutionTime = 0;

  return function (...args) {
    const now = Date.now();
    const remainingTime = limit - (now - lastExecutionTime);
    const context = this;

    if (remainingTime <= 0) {
      fn.apply(context, args);
      lastExecutionTime = now;
    } else if (!timeoutId) {
      timeoutId = setTimeout(() => {
        fn.apply(context, args);
        lastExecutionTime = now + remainingTime;
        timeoutId = null;
      }, remainingTime);
    }
  };
}

// 예제 함수
function greet() {
  console.log('스로틀:', Math.abs(22.22));
}

// 클릭 이벤트 처리
window.addEventListener('click', throttleByTimestamp(greet, 1000));

결론:

디바운스: 여러 번의 연속적인 작업을 하나의 작업으로 합칩니다. 기본 원리는 지연 타이머를 유지하며, 지정된 시간 이후에 함수를 실행하지만, 해당 시간 내에 다시 트리거되는 경우 이전 타이머를 취소하고 새로 설정합니다.

스로틀: 특정 시간 동안 함수가 단 한 번만 실행되도록 합니다. 기본 원리는 지연된 호출이 아직 실행 중인지 확인하는 것입니다.

차이점: 스로틀은 이벤트가 얼마나 자주 발생하든 상관없이 반드시 지정된 시간 내에 최소 한 번은 실제 이벤트 핸들러를 실행합니다. 반면, 디바운스는 마지막 이벤트 이후에 단 한 번만 함수를 실행합니다. 예를 들어, 페이지 스크롤 중 일정 시간마다 AJAX 요청을 보내야 하는 무한 스크롤 시나리오에서는 스로틀이 더 적합합니다.

태그: JavaScript Debounce Throttle

7월 7일 19:48에 게시됨