debounce? throttle?

55555-Jyeon·2024년 4월 1일
1

Deep Dive

목록 보기
1/8
post-thumbnail
post-custom-banner

디바운싱(Debouncing)과 쓰로틀링(Throttling)은 자바스크립트의 개념이라기 보다는 프로그래밍 기법중 하나입니다. 둘 다 디바이스에게 무리를 주지 않기 위해 사용되곤 합니다. 일종의 최적화라고 볼 수 있습니다.

Throttle와 Debounce는 자주 사용 되는 이벤트나 함수들이 실행되는 빈도를 줄여서 성능 상의 유리함을 가져오기 위한 개념입니다.

자주 사용되는 간단한 예로 자동 완성을 들 수 있습니다.

키보드가 한자씩 입력될 때마다 api로 데이터를 가져오게 되면 사용자의 의도와 무관한 요청이 자주 발생하게 됩니다. 이를 줄이기 위해 입력이 끝난 후나 입력되는 중간 중간 특정 시간(ms)마다 api 값을 가져온다면 성능에서 매우 유리해지게 됩니다.

Throttle은 입력 주기를 방해하지 않고 일정 시간 동안의 입력을 모아서 한 번에 출력을 제한하는 것이고 Debounce 는 입력 주기가 끝나면 출력하게 합니다.

위 예제에서 Throttle은 특정 시간마다 api 값을 가져오는 것이고, Debounce 는 입력이 끝난후 api 값을 가져오는 것입니다.

🏈 Debounce

사전에 등록된 의미

debounce 는 사전에 등재된 단어는 아닙니다.
Debouncing이라는 단어만 컴퓨터 사이언스 용어로 등재되어 있습니다.

위 내용을 번역하면 아래와 같습니다.

Debouncing은 시간이 많이 걸리는 작업이 너무 자주 실행되어 웹 페이지의 성능이 저하되지 않도록 하는 데 사용되는 프로그래밍 방식입니다.
즉, 함수가 호출되는 속도를 제한합니다. JavaScript의 디바운싱은 브라우저 성능을 향상시키는 데 사용되는 방식입니다.

전자 쪽에서도 bouncing 이라는 용어가 있습니다.
스위치들이 접점에서 떨어지거나 붙는 시점에 물리적으로 미세하게 여러 번의 on/off 가 되는 현상을 뜻합니다.

이는 의도했던 바가 아니므로 방지하는 게 좋습니다.
그런 의미에서 이런 불필요한 튀는 현상( 여러 on/off 발생)을 방지하는 의미에서 debouncing이라고 표현한 것 같습니다. 처음에 말했던 '여러 이벤트가 발생할 때, 일정 그룹으로 묶어서 하나로 처리'하는 debouncing의 의미와 어느 정도 부합한다고 볼 수 있습니다.


다시 한 번 정리하자면:
Debounce는 여러번 발생하는 이벤트에서 가장 마지막 이벤트만을 실행 되도록 만드는 개념입니다. 그리고 가장 마지막 이벤트만을 실행해 성능성 유리함을 가져올 수 있습니다.

debounce example


1️⃣ scroll

스크롤 이벤트에 debounce를 적용하는 경우, 일정 시간 동안 스크롤 이벤트가 여러 번 발생하더라도 마지막 스크롤 위치만 사용하여 처리됩니다. 일반적으로 스크롤 이벤트는 사용자가 스크롤을 할 때마다 많은 양의 이벤트가 연속적으로 발생할 수 있습니다. 이런 경우에 모든 스크롤 이벤트를 처리하면 성능이 저하될 수 있습니다.

따라서 debounce를 적용하면, 연속적으로 발생하는 스크롤 이벤트를 일정 시간 동안 무시하고, 마지막 스크롤 위치만 고려하여 한 번만 처리합니다. 이렇게 함으로써 성능을 향상시킬 수 있으며, 사용자 경험을 개선할 수 있습니다. debounce를 사용하면 스크롤 이벤트가 연속적으로 발생할 때마다 처리되는 것이 아니라, 일정 시간이 지난 후에 한 번만 처리되므로 스크롤 이벤트에 대한 응답이 부드럽고 효율적으로 이루어집니다.



2️⃣ input

debounce는 입력 값이 변경될 때마다 즉시 반영되지 않고, 입력이 멈춘 후에 일정 시간이 지난 후에 반영됩니다. 따라서 debounce를 적용한 input 창에는 입력이 발생할 때마다 입력 값이 즉시 반영되지 않고, 입력이 멈춘 후에 일정 시간이 지난 후에 입력 값이 반영됩니다.

예를 들어, debounce를 적용한 input 창에서 사용자가 문자를 입력할 때마다 입력 값이 바로 반영되지 않고, 사용자가 일정 시간동안 입력을 멈춘 후에 입력 값이 반영됩니다. 이렇게 함으로써 사용자가 입력을 마치고 입력값을 사용할 때까지 기다리는 동안 입력값이 계속 변경되는 것을 방지할 수 있습니다.

위 input을 활용할 수 있는 방법은 아래와 같습니다.

| 검색 기능
사용자가 검색어를 입력할 때마다 검색을 실행하는 것이 아니라, 사용자가 입력을 멈춘 후 일정 시간이 지난 후에 검색을 실행합니다. 이렇게 함으로써 사용자가 입력하는 동안 매번 검색을 실행하지 않고, 입력이 완료된 후에 한 번만 검색을 실행하여 서버 부하를 줄일 수 있습니다.

| 자동 완성 기능
사용자가 입력하는 동안 매번 자동 완성 기능을 실행하지 않고, 입력이 멈춘 후 일정 시간이 지난 후에 자동 완성을 실행합니다. 이렇게 함으로써 사용자가 입력을 마친 후에 자동 완성이 제공되므로 사용자 경험이 개선됩니다.


usuage

1️⃣ 검색 기능
사용자가 검색어를 입력할 때마다 실시간으로 검색을 수행하는 경우, 사용자가 입력을 멈추고 일정 시간이 지난 후에 검색을 수행하도록 debounce를 적용할 수 있습니다. 이렇게 함으로써 사용자가 입력하는 동안 계속해서 검색 요청이 발생하는 것을 방지하고, 사용자 경험을 향상시킬 수 있습니다.

2️⃣ 자동 완성 기능
사용자가 입력하는 동안 자동 완성 기능을 제공할 때 debounce를 사용하여 입력이 멈춘 후 일정 시간이 지난 후에 자동 완성을 수행하도록 할 수 있습니다. 이는 사용자가 입력을 마치기 전에 너무 자주 자동 완성이 발생하는 것을 방지하고, 사용자가 원하는 결과를 더 쉽게 찾을 수 있도록 도와줍니다.

3️⃣ resize 이벤트 처리
브라우저 창 크기가 변경될 때마다 발생하는 리사이즈 이벤트를 debounce를 사용하여 처리할 수 있습니다. 사용자가 창 크기를 변경하는 동안 이벤트가 계속해서 발생하는 것을 방지하고, 창 크기 조정이 멈춘 후에 이벤트를 처리하여 불필요한 처리를 줄일 수 있습니다.

4️⃣ 텍스트 입력
사용자가 텍스트를 입력할 때마다 입력값을 실시간으로 처리하는 경우, debounce를 사용하여 입력이 멈춘 후에 처리를 수행할 수 있습니다. 이는 사용자가 입력을 멈추기 전까지 불필요한 처리를 하지 않도록 도와주고, 성능을 향상시킬 수 있습니다.

이렇게 debounce는 입력 또는 이벤트가 발생하는 동안 일정 시간 동안 다음 입력 또는 이벤트를 기다리는 것을 가능하게 하여, 불필요한 이벤트 핸들러의 호출 빈도를 제어하고 성능을 최적화하는 데 유용합니다.


difference

Throttle과 다른 점은, 마지막 이벤트에서 일정 시간동안 이벤트가 발생할 경우 또 일정 시간을 기다린다는 점입니다.



🚰 Throttle

사전에 등록된 의미

이것 외에도 쓰이는 의미를 보면:
보통 무언가를 '조이거나 조르는' 의미를 담고 있습니다. throttling은 '압력 조절' 이라는 뜻을 가지고 있습니다.
자바스크립트 혹은 컴퓨터 사이언스에서도 마찬가지의 의미를 담고있습니다.

요청 혹은 이벤트가 의도한 바보다 너무 과도하게 발생할 때 일정 delay를 주고 delay 동안은 수도꼭지를 조여버리는 것입니다. 그 기간동안 발생한 이벤트, 요청, 함수 등은 무시가 되는 것이고요.

Throttle은 여러 번 발생하는 이벤트를 일정 시간 동안, 한번만 실행 되도록 만드는 개념입니다. 한 번만 실행 때문에 잦은 이벤트 발생을 막아 성능상의 유리함을 가져 올 수 있습니다.

throttle example

1️⃣ scroll

일반적인 스크롤 이벤트와 throttle를 적용한 스크롤 이벤트의 주요 차이점은 이벤트 핸들러의 호출 빈도와 업데이트 속도에 있습니다.

| 이벤트 핸들러 호출 빈도

일반적인 스크롤 이벤트에서는 스크롤이 발생할 때마다 이벤트 핸들러가 호출됩니다. 이는 사용자가 스크롤을 조작할 때마다 많은 양의 이벤트가 발생할 수 있음을 의미합니다.
throttle를 적용한 스크롤 이벤트에서는 일정 시간 동안 한 번만 이벤트 핸들러가 호출됩니다. 이는 사용자가 스크롤을 조작할 때 이벤트 핸들러가 너무 자주 호출되는 것을 방지하고, 일정 시간 간격으로만 스크롤 위치를 업데이트하여 성능을 향상시킵니다.

| 업데이트 속도

일반적인 스크롤 이벤트에서는 스크롤이 발생할 때마다 즉시 스크롤 위치가 업데이트됩니다. 따라서 스크롤이 빠르게 발생할 경우에는 스크롤 위치의 업데이트가 매우 빠르게 이루어지게 됩니다.
throttle를 적용한 스크롤 이벤트에서는 일정 시간 동안 한 번만 스크롤 위치가 업데이트됩니다. 따라서 사용자가 스크롤을 조작할 때마다 즉시 반응하지 않고, 일정 시간 간격으로만 스크롤 위치가 업데이트됩니다. 이는 부드러운 스크롤 경험을 제공할 수 있으며, 스크롤 이벤트에 대한 불필요한 처리를 줄여 성능을 개선할 수 있습니다.
따라서 throttle를 적용한 스크롤 이벤트는 이벤트 핸들러의 호출 빈도를 제어하고 업데이트 속도를 조절하여 사용자 경험을 개선하고 성능을 최적화하는 데 도움이 됩니다.


2️⃣ input

일반 input과 throttle이 적용된 input의 가장 큰 차이는 사용자 입력에 대한 처리 방식입니다. 일반 input은 사용자가 입력할 때마다 즉시 이벤트가 발생하고 해당 이벤트 핸들러가 실행되어 입력값이 업데이트됩니다. 반면에 throttle이 적용된 input은 입력에 대한 이벤트 핸들러 호출을 제어하여 일정 시간 동안 여러 번의 입력에 대한 핸들러 호출을 제한합니다.

여기에는 몇 가지 차이점이 있습니다.

| 이벤트 핸들러 호출 빈도
throttle이 적용된 input의 경우 일정 시간 간격으로만 이벤트 핸들러가 호출되므로, 사용자가 빠르게 입력을 하더라도 핸들러의 호출 빈도가 제한됩니다. 반면에 일반 input은 사용자의 입력에 따라 즉시 핸들러가 호출되므로, 빠른 입력에 더 많은 이벤트 핸들러 호출이 발생할 수 있습니다.

| 업데이트 속도
throttle이 적용된 input은 일정 시간 간격으로만 입력값이 업데이트되므로, 사용자가 입력하는 동안 입력값이 즉시 업데이트되지 않을 수 있습니다. 이는 입력값의 업데이트 속도가 느려질 수 있음을 의미합니다. 반면에 일반 input은 사용자의 입력에 따라 즉시 입력값이 업데이트되므로, 더 빠른 업데이트 속도를 제공할 수 있습니다.

따라서 throttle이 적용된 input은 입력값의 업데이트 속도를 제어하고, 사용자의 빠른 입력에 따른 이벤트 핸들러 호출을 제한하여 성능을 최적화할 수 있습니다. 그러나 사용자에게는 결과적으로 비슷하게 보일 수 있습니다.



usuage

throttle은 다양한 상황에서 사용될 수 있지만, 주로 다음과 같은 경우에 많이 활용됩니다.

1️⃣ 사용자 입력 이벤트 처리

사용자가 입력하는 이벤트(예: 텍스트 입력, 마우스 이동 등)를 처리할 때 throttle을 사용하여 이벤트 핸들러의 호출 빈도를 제한할 수 있습니다. 이를 통해 사용자의 빠른 입력에 따른 불필요한 연산을 줄이고 성능을 향상시킬 수 있습니다.

2️⃣ scroll 이벤트 처리
스크롤 이벤트와 같이 빈번하게 발생하는 이벤트를 throttle을 적용하여 처리할 수 있습니다. 스크롤 이벤트는 화면이 스크롤될 때마다 발생하므로, 너무 자주 발생하는 경우에는 throttle을 적용하여 스크롤 이벤트 핸들러의 호출 빈도를 제어하여 성능을 최적화할 수 있습니다.

3️⃣ resize 이벤트 처리
창 크기가 변경될 때 발생하는 리사이즈 이벤트도 throttle을 사용하여 처리할 수 있습니다. 창 크기가 변경될 때마다 레이아웃이 재배치되는 경우가 많으므로, throttle을 적용하여 리사이즈 이벤트 핸들러의 호출 빈도를 제어하여 성능을 향상시킬 수 있습니다.

4️⃣ API 요청 제어
API 요청을 throttle을 사용하여 제어할 수 있습니다. 사용자가 빠르게 연속적인 요청을 보내는 경우에는 throttle을 적용하여 일정 시간 동안 한 번만 요청을 보내도록 제어할 수 있습니다. 이를 통해 서버 부하를 줄이고 성능을 개선할 수 있습니다.

최적화에 가장 유용하게 쓰일 때는 사용자 입력과 같이 빈번하게 발생하는 이벤트 처리나 API 요청 제어 등에서 throttle을 사용하는 경우입니다. throttle을 적용함으로써 이벤트 핸들러의 호출 빈도를 제어하고 불필요한 연산을 줄이므로, 성능을 최적화하고 웹 애플리케이션의 반응성을 향상시킬 수 있습니다.


difference

Debounce와 다른 점은 이벤트 발생 시간 이후에 일정 시간 동안만을 기다리고, 이벤트를 실행 후 재차 기다린다는 점입니다.



Throttle 와 Debounce 차이점

Throttle 와 Debounce 의 차이점은 이벤트를 언제 발생 시킬지의 시점 차이이다.

Debounce 는 입력이 끝날때까지 무한적으로 기다리지만 Throttle 는 입력이 시작되면 일정 주기로 계속 실행합니다. Debounce 의 시간을 짧게 가져간다면 Throttle 와 비슷한 효과가 날 수 있지만 그럼에도 시점에서 차이가 날 수 있습니다.
때문에 작업물의 성격에 따라 사용방법이 달라질 수 있습니다.

대표적인 예로 자동완성 만들 경우, 일정 주기로 자동으로 완성되는 리스트를 보여주는 것에는 사용자 측면에서 Throttle (검색 되는 경험) 가 유리할 수 있지만, 성능상에서는 Debounce (1번만 호출) 가 훨씬 유리할 수 있습니다.



libraries

throttle-debounce

throttle-debounce 라이브러리를 이용하면, 매우 쉽게 throttle 와 debounce 개념을 사용할 수 있습니다.

throttle-debounce는 입력 또는 이벤트 핸들러의 호출 빈도를 제어하기 위한 라이브러리입니다. 이 라이브러리는 throttle과 debounce를 모두 제공하며, 주로 사용자 입력 처리나 이벤트 핸들러의 호출을 최적화하는 데 활용됩니다.

throttle-debounce는 입력이 발생할 때마다 이벤트 핸들러의 호출 빈도를 제한하거나, 입력이 멈춘 후 일정 시간이 지난 후에 이벤트 핸들러를 호출하는 등의 기능을 쉽게 구현할 수 있습니다.


code sample

import { throttle } from 'throttle-debounce';

// 버튼 클릭 이벤트 핸들러
const handleClick = throttle(1000, () => {
  console.log('Button clicked with throttle');
});

// 버튼 클릭 이벤트에 핸들러 연결
document.querySelector('button').addEventListener('click', handleClick);
import { debounce } from 'throttle-debounce';

// 입력 이벤트 핸들러
const handleInput = debounce(1000, (event) => {
  console.log('Input debounced:', event.target.value);
});

// 입력 이벤트에 핸들러 연결
document.querySelector('input').addEventListener('input', handleInput);

위의 예시에서 throttle-debounce 라이브러리의 throttle 함수는 지정된 시간 간격 동안에 한 번만 이벤트를 처리하도록 하고, debounce 함수는 이벤트가 발생한 후 지정된 시간이 지난 후에 이벤트를 처리합니다.



라이브러리 특징

1️⃣ Throttle 기능
입력이 발생할 때 일정 시간 동안 한 번만 이벤트 핸들러를 호출하도록 설정할 수 있습니다. 이는 사용자가 빠르게 연속적인 입력을 하더라도 이벤트 핸들러의 호출 빈도를 제어하여 성능을 최적화할 수 있습니다.

2️⃣ Debounce 기능
입력이 발생한 후 일정 시간이 지난 후에 이벤트 핸들러를 호출하도록 설정할 수 있습니다. 이는 사용자 입력이 멈춘 후 일정 시간이 지나기 전에는 이벤트 핸들러를 호출하지 않고, 입력이 멈춘 후에 한 번만 호출하여 성능을 최적화할 수 있습니다.

3️⃣ 유연성
라이브러리를 사용하여 다양한 입력 또는 이벤트에 throttle과 debounce를 적용할 수 있습니다. 이는 사용자 입력 처리, 스크롤 이벤트 처리, API 요청 제어 등 다양한 상황에서 유용하게 사용될 수 있습니다.

throttle-debounce 라이브러리는 다른 라이브러리와 함께 사용될 수도 있고, 개발자가 직접 구현할 수도 있지만, 일반적으로 라이브러리를 사용하는 것이 더 편리하고 코드를 간결하게 유지할 수 있습니다. 🙂



lodash

lodash는 자바스크립트 유틸리티 라이브러리로, 많은 개발자들이 프로젝트에서 사용하는 강력한 도구 중 하나입니다. Lodash는 다음과 같은 특징을 가지고 있습니다.

특징

1️⃣ 유틸리티 함수 제공
Lodash는 다양한 유틸리티 함수를 제공하여 개발자가 자주 사용하는 다양한 작업을 간편하게 처리할 수 있도록 도와줍니다. 예를 들어, 배열 및 객체 조작, 함수 작업, 문자열 조작, 숫자 처리 등 다양한 유틸리티 함수를 제공합니다.

2️⃣ croll platform 호환성
Lodash는 크로스 플랫폼 호환성을 가지고 있어 브라우저 및 Node.js와 같은 서버 환경에서 모두 사용할 수 있습니다. 이는 프로젝트의 환경에 관계없이 일관된 코드를 작성할 수 있음을 의미합니다.

3️⃣ 성능 최적화
Lodash는 내부적으로 성능 최적화가 잘 이루어져 있어, 많은 경우에 빠르고 효율적으로 동작합니다. 이는 대용량 데이터나 복잡한 작업을 처리할 때 유용합니다.

4️⃣ method chaining
Lodash는 메서드 체이닝을 통해 여러 유틸리티 함수를 연속적으로 호출할 수 있도록 지원합니다. 이를 통해 코드를 간결하게 유지하고 가독성을 높일 수 있습니다.

5️⃣ 모듈화
Lodash는 각 유틸리티 함수를 개별적으로 제공하므로 필요한 함수만 선택적으로 가져와서 사용할 수 있습니다. 이는 번들 크기를 최소화하고 프로젝트의 성능을 향상시킬 수 있습니다.



code sample

  // 일반적인 input 이벤트 처리
  const [normalInputValue, setNormalInputValue] = useState("");
  const handleNormalInputChange = (event) => {
    setNormalInputValue(event.target.value);
  };

  // Throttle를 적용한 input 이벤트 처리
  const [throttledInputValue, setThrottledInputValue] = useState("");
  const handleThrottledInputChange = throttle((event) => {
    setThrottledInputValue(event.target.value);
  }, 500);

  const [debouncedInputValue, setDebouncedInputValue] = useState("");

  // Debounce를 적용한 input 이벤트 처리
  const handleDebouncedInputChange = debounce((event) => {
    setDebouncedInputValue(event.target.value);
  }, 500);


RxJS

RxJS는 Reactive Extensions for JavaScript의 약어로, JavaScript를 위한 반응형 프로그래밍 라이브러리입니다. RxJS는 비동기적이고 이벤트 기반의 프로그래밍을 다루는데 사용되며, 데이터 스트림과 데이터 시퀀스를 다루는데 주로 사용됩니다.

RxJS는 비동기적인 작업을 다루는데 효과적이며, 복잡한 비동기 코드를 간결하고 읽기 쉽게 작성할 수 있도록 도와줍니다. 또한 RxJS는 프론트엔드 및 백엔드에서 모두 사용될 수 있으며, 다양한 애플리케이션에서 상태 관리, 이벤트 처리, HTTP 요청 등 다양한 용도로 활용됩니다.



특징

1️⃣ Observables(옵저버블)
옵저버블은 비동기적인 데이터 스트림을 나타내는 객체입니다. 이러한 데이터 스트림은 시간에 따라 변할 수 있으며, 옵저버블은 데이터 스트림을 생성하고 이를 관찰할 수 있는 메서드를 제공합니다.

2️⃣ Observers(옵저버)
옵저버는 옵저버블의 데이터 스트림을 관찰하고, 이벤트를 처리하는 콜백 함수를 가지고 있는 객체입니다. 옵저버는 옵저버블에서 발생하는 이벤트에 대응하여 특정 동작을 수행합니다.

3️⃣ Operators(연산자)
연산자는 옵저버블의 데이터 스트림을 변형하거나 필터링하는 함수형 프로그래밍 기법을 제공합니다. RxJS에는 다양한 연산자가 제공되며, 이를 사용하여 옵저버블의 데이터를 변형하거나 조작할 수 있습니다.

4️⃣ Subscription(구독)
구독은 옵저버블과 옵저버 간의 연결을 나타냅니다. 구독은 옵저버블의 데이터 스트림을 구독하고, 옵저버블에서 발생하는 이벤트를 옵저버에게 전달합니다.

5️⃣ Subjects(서브젝트)
서브젝트는 옵저버블과 옵저버의 역할을 모두 수행할 수 있는 특별한 종류의 객체입니다. 서브젝트는 데이터를 발행하고 구독할 수 있으며, 다른 옵저버블과 마찬가지로 연산자를 적용할 수 있습니다.



code sample

import { fromEvent } from 'rxjs';
import { throttleTime } from 'rxjs/operators';

const button = document.querySelector('button');

// 버튼 클릭 이벤트를 옵저버블로 변환
const buttonClick$ = fromEvent(button, 'click');

// 버튼 클릭 이벤트를 1초 간격으로 방출하도록 throttle 적용
const throttledButtonClick$ = buttonClick$.pipe(
  throttleTime(1000)
);

// throttle이 적용된 버튼 클릭 이벤트 구독
throttledButtonClick$.subscribe(event => {
  console.log('Button clicked with throttle:', event);
});
import { fromEvent } from 'rxjs';
import { debounceTime } from 'rxjs/operators';

const input = document.querySelector('input');

// 입력 이벤트를 옵저버블로 변환
const inputEvent$ = fromEvent(input, 'input');

// 입력 이벤트를 1초 간격으로 디바운스 적용
const debouncedInputEvent$ = inputEvent$.pipe(
  debounceTime(1000)
);

// debounce가 적용된 입력 이벤트 구독
debouncedInputEvent$.subscribe(event => {
  console.log('Input debounced:', event.target.value);
});

위의 예시에서 throttleTime은 일정 시간 동안에 한 번만 이벤트를 방출하도록 하고, debounceTime은 마지막 이벤트가 발생한 후 일정 시간이 지난 후에만 이벤트를 방출하도록 합니다.



References.

https://pks2974.medium.com/throttle-%EC%99%80-debounce-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0-2335a9c426ff
https://webclub.tistory.com/607

profile
🥞 Stack of Thoughts
post-custom-banner

2개의 댓글

comment-user-thumbnail
2024년 4월 8일

디바운스 쓰로틀링 마스터 되셨겠는데요..?!

답글 달기