본문 바로가기

FrontEnd

Vue3로 debounce, throttle 구현하기

반응형

debounce 및 throttle은 함수 호출을 제한하여
이벤트 핸들러 호출 빈도를 줄일 수 있는 두 가지 기술입니다.

이 두 가지를 잘 활용하면 애플리케이션의 성능을 크게 향상시킬 수 있습니다.
Vue 애플리케이션에서 watcher와 이벤트 핸들러를 debounce, throttle 하는 방법을 배워봅시다.

Vue3 Logo

Debounce 함수 만들기

디바운싱은 일정 시간이 지날 때까지 이벤트 트리거를 대기하여 애플리케이션의 성능을 개선할 수 있는 기술입니다.
디바운스 함수는 재실행되기 전에 설정된 시간 동안 대기할 수 있습니다.
ex) 사용자 입력에 의한 네트워크 요청 제한, 화면 업데이트 제한

다음은 debounce 함수의 코드 스니펫입니다.

export function debounce(fn, wait){
    let timer;
   return function(...args){
     if(timer) {
        clearTimeout(timer); // clear any pre-existing timer
     }
     const context = this; // get the current context
     timer = setTimeout(()=>{
        fn.apply(context, args); // call the function if time expires
     }, wait);
   }
}

debounce 함수는 디바운스할 함수와 대기 시간(밀리초)의 두 가지 인수를 사용합니다.
해당 함수는 나중에 호출할 수 있는 함수를 반환합니다.

const debouncedFunction = debounce(function() { ... }, 300);
console.log(typeof debouncedFunction); // `function`
// When the debounce function is triggered:

위의 코드는 기존 제한 시간을 취소하고 인수로 전달받은 대기 시간에 따라 새 대기 시간을 설정합니다.
대기 시간이 만료되면 인수를 사용하여 콜백 함수를 호출합니다.


Throttle 함수 만들기

debounce는 사용자가 특정 시간 동안 이벤트를 수행하지 않았을 때 함수를 호출하는 반면,
throttle은 사용자가 이벤트를 수행하는 동안 설정된 시간 간격으로 함수를 호출합니다.

예를 들어 300밀리초 타이머로 search 기능을 debounce하면
사용자가 300밀리초 동안 검색을 수행하지 않은 경우에만 함수가 호출됩니다.
그러나 search 함수를 300밀리초로 throttle하면 사용자가 입력하는 동안 300밀리초마다 함수가 호출됩니다.
 
다음 예제는 throttle 함수 코드 스니펫입니다.
export function throttle(fn, wait){
    let throttled = false;
    return function(...args){
        if(!throttled){
            fn.apply(this,args);
            throttled = true;
            setTimeout(()=>{
                throttled = false;
            }, wait);
        }
    }
}

throttle 함수가 트리거되면 throttled 변수가 false로 설정되며
제공된 함수가 인수와 함께 호출됩니다.

 

함수 호출 후 throttled 변수를 true로 설정합니다.
인수로 정해진 시간 내에 이벤트가 발생하면 throttle 변수가 true로 설정될 때까지 함수가 호출되지 않습니다.
setTimeout은 대기 시간이 만료된 후 throttled에 변수를 할당하는 역할을 합니다.

Watcher 디바운스하기

사용자가 텍스트 상자에 값을 입력할 때 Fetch API를 호출하고 값을 기록하는 간단한 컴포넌트를 만들어 보겠습니다.

<template>
 <div id="app">
  <input v-model="value" type="text" />
  <p>{{ value }}</p>
</div>
</template>
<script>
export default {
  data() {
    return {
      value: "",
    };
  },
  watch: {
    value(newValue, oldValue) {
      console.log("value changed: ", newValue, oldValue);
      // call fetch API to get results
    }
  }
};
</script>​
위의 코드는 사용자가 값을 입력할 때마다 콘솔에 로그가 출력되고 API를 호출합니다.
API를 너무 자주 호출하면 앱 성능이 저하됩니다.
따라서 위의 활동을 디바운스하고 이 디바운스된 함수를 watcher 내부에서 호출합니다.
이를 위해 앞에서 만든 debounce 함수를 사용할 수 있습니다.
<template>
 <div id="app">
  <input v-model="value" type="text" />
  <p>{{ value }}</p>
</div>
</template>
<script>
import {debounce} from "./Utils.js";
export default {
  data() {
    return {
      value: "",
    };
  },
  created(){
     this.debouncedFetch = debounce((newValue, oldValue)=>{
            console.log("value changed: ", newValue, oldValue);
           // call fetch API to get results
     }, 1000);
  },
  watch: {
    value(...args) {
      this.debouncedFetch(...args);
    }
  }
};
</script>
위의 코드는 사용자 마지막 타이핑 이후 1000밀리초가 경과한 경우 콘솔에 로깅하거나 API를 호출할 수 있습니다.
주 : 검색 목록 갱신은 watch를 이용해 목록 갱신을 디바운스
콜백과 대기 시간으로 디바운스 함수를 호출하는 debouncedFetch의 인스턴스를 생성하여 watcher에서 디바운싱을 구현합니다.
이 인스턴스는 created() 훅에서 생성된 다음 watch 내부의 인수를 사용하여 debouncedFetch를 호출합니다.

이벤트 핸들러 디바운스하기

watch와 이벤트 핸들러의 디바운싱은 유사합니다.
사용자가 텍스트 상자에 값을 입력하는 동일한 예를 고려해 보겠습니다.

입력 후 콘솔에 로깅하고 Fetch API를 호출합니다.

<template>
  <input @input="onChangeDebounced" type="text" />
</template>
<script>
import {debounce} from './Utils.js';
export default {
  created() {
    this.onChangeDebounced = debounce(event => {
      console.log('changed value:', event.target.value);
      // call fetch API to get results
    }, 1000);
  },
};
</script>

참고

https://blog.logrocket.com/debounce-throttle-vue/

 

How to debounce and throttle in Vue - LogRocket Blog

debounce and throttle are two techniques that can improve application performance by slowing down event handlers.

blog.logrocket.com

시간나면 위 예제를 TS +  setup API로 변경할 예정

반응형