본문 바로가기
dev/javascript

[javascript] 자바스크립트 debounce 함수 지연 시키기

by 최연탄 2023. 3. 19.
728x90
반응형

참고: https://www.freecodecamp.org/news/javascript-debounce-example/

JavaScript에서 debounce 기능은 사용자 입력당 한 번만 코드가 트리거되도록 합니다. 사용 사례로는 검색 추천, 텍스트 필드 자동 저장 및 버튼 연속 클릭 제거 등이 있습니다.

이 포스트에서는 JavaScript로 debounce 함수를 만드는 방법에 대해 알아보겠습니다.

debounce 란?

디바운스라는 용어는 전자 공학에서 부터 시작됐습니다. 예를 들어 TV 리모컨을 누르는 경우 버튼의 신호가 리모컨의 마이크로칩으로 너무 빨리 전달되어 버튼에서 손을 떼기 전에 신호가 튀어 마이크로칩이 "클릭"을 여러 번 인식하는 경우입니다.

https://www.freecodecamp.org/news/javascript-debounce-example/

이를 개선하려면 버튼 신호를 받은 경우 물리적으로 버튼을 다시 누를 수 없다고 생각되는 몇 마이크로초 동안 버튼 신호 처리를 중지하게 하는 것 입니다.

JavaScript에서의 debounce

JavaScript에서의 사용 사례도 위와 비슷합니다. 함수를 실행하고 싶지만 케이스당 한 번만 실행하고 싶을 때 입니다.

사용자가 검색어 입력을 마친 후에만 검색어에 대한 추천을 표시하고자 한다고 가정해 보겠습니다.

또는 양식 입력 시 사용자가 입력을 마쳤을 때만 양식의 변경 사항을 저장하려 할 때를 생각해 볼 수도 있습니다. 모든 저장에는 데이터베이스 비용이 들기 때문입니다.

그리고 윈도우에 익숙해진 사람들이 모든 것을 두번 클릭할 때도 적용할 수 있습니다.

다음은 디바운스 함수의 간단한 구현입니다:

function debounce(func, timeout = 300){
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => { func.apply(this, args); }, timeout);
  };
}

function saveInput(){
  console.log('Saving data');
}

const processChange = debounce(() => saveInput());

위의 코드는 input에 사용할 수 있습니다:

<input type="text" onkeyup="processChange()" />

또는 버튼에:

<button onclick="processChange()">Click me</button>

또는 이벤트 리스너에:

window.addEventListener("scroll", processChange);

다른 요소에 대해서도 마찬가지로 사용할 수 있습니다.

See the Pen debounce by shinyks (@shinyks) on CodePen.

무슨 일이 벌어진 걸까요? debounce는 두 가지 작업을 다루는 특수 함수 입니다.

  • timer 변수에 scope 할당
  • 특정 시간에 함수가 실행되도록 예약

문자열 입력 예제를 사용하여 이 기능이 어떻게 작동하는지 설명하겠습니다.

사용자가 첫 번째 글자를 쓰고 키를 놓으면 디바운스는 먼저 clearTimeout(timer)을 사용하여 타이머를 재설정합니다. 이 시점에서는 아직 예약된 것이 없으므로 다른 단계가 필요하지 않습니다. 그런 다음 콜백 함수(saveInput())가 300ms 내에 호출되도록 예약합니다.

하지만 사용자가 계속해서 글을 쓴다고 가정해 봅시다. 이 때는 키를 놓을 때마다 디바운스가 다시 실행됩니다. 모든 호출은 타이머를 재설정합니다. 즉, 콜백 함수를 호출하려던 이전 계획을 취소하고 미래의 300ms 뒤의 새 시간으로 다시 예약합니다. 사용자가 300ms 미만의 속도로 키를 계속 누르면 콜백 함수 호출이 계속 밀립니다.

마지막 예약은 취소되지 않았으므로 콜백 함수가 최종적으로 실행됩니다.

반대로 후속 이벤트 무시하는 방법

디바운스는 자동 저장을 하거나 추천을 표시하는데 좋습니다. 그런데 한 번만 클릭해야하는 버튼을 여러번 클릭하는 경우는 어떨까요? 마지막 클릭을 기다리는게 아니라 첫 번째 클릭만 실행하고 나머지는 무시하는 방법이 있습니다.

function debounce_leading(func, timeout = 300){
  let timer;
  return (...args) => {
    if (!timer) {
      func.apply(this, args);
    }
    clearTimeout(timer);
    timer = setTimeout(() => {
      timer = undefined;
    }, timeout);
  };
}

위의 코드를 적용하면 첫 번째 버튼 클릭으로 인해 발생한 첫 번째 debounce_leading 호출에 대해 콜백 함수를 실행합니다. 그리고 300ms 후에 타이머 소멸을 예약합니다. 해당 시간 내의 모든 후속 클릭에는 타이머가 이미 존재하게 되고 타이머 소멸을 300ms씩 미룹니다.

라이브러리의 debounce 구현

이 포스트에서는 JavaScript로 debounce 기능을 구현하고 웹 사이트 요소에 의해 실행된 이벤트에 debounce를 적용하는 방법을 알아봤습니다. 하지만 구현을 원하지 않는 경우 직접 구현하지 않아도 됩니다. 널리 사용되는 JavaScript 라이브러리에 이미 구현이 포함되어 있습니다. 다음은 몇 가지 예입니다.

Library Example
jQuery $.debounce(300, saveInput);
Loadsh _.debounce(saveInput, 300);
Underscore _.debounce(saveInput, 300);
반응형

댓글