Debounce와 Throttle: 직접 실행하며 알아보기

연속된 함수 호출에 대처하는 방법들

Table Of Contents

0. TL;DR

1. Debounce와 Throttle을 사용하는 이유

웹 서비스에서는 사용자가 클릭하거나 키보드를 입력하는 등의 액션을 통해서 이벤트가 일어난다.

그런데 화면을 스크롤하거나(scroll) 키보드 입력을 하거나(keyup, keydown), 화면 크기를 조절하는(resize) 액션 등은 매우 빠른 속도로 연속해서 일어날 수 있다.

이런 이벤트들에 일일히 반응하게 되면 렌더링이 느려지거나, 심지어는 브라우저가 멈춰버릴 수도 있다🥹

 

이런 문제를 해결하기 위해 디바운스(Debounce)스로틀(Throttle) 이라는 개념이 등장한다.

2. 디바운스(Debounce)

디바운스(Debounce) 란, 너무 짧은 간격 내에 발생한 작업들을 버리고, 한 번의 호출로 통합하는 방법이다.

즉, 이벤트를 하나의 그룹으로 묶어서 처리한다. 이를 위해서 일정 시간 동안 호출이 멈출 때까지 작업의 실행을 미루게 된다.

2.1. 디바운스 예시: 검색

사용자가 입력하는 내용을 받아서 검색 결과를 표시하는 상황을 생각해보자.

이런 경우에 search 함수를 디바운스해서 사용자의 입력이 멈출 때만 search 함수를 수행하도록 제한할 수 있다.

2.2. 디바운스 실행해보기

함수를 디바운싱하면 이런 과정을 거쳐 함수 실행이 일어난다.

  1. search 호출이 일어난다. (이 호출은 leading edge라고 부른다)
  2. 다음으로 search 함수의 호출이 첫 호출(leading edge)로부터 일정 시간(ex. 10ms) 이내에 일어난다면, 이 호출은 첫 호출과 같은 batch에 있다고 한다.
  3. search의 마지막 호출 이후로 일정 시간이 지나도 추가적인 호출이 없다면, trailing edge에 도달했다고 한다.

보통 디바운싱된 함수는 trailing edge에서만 실행되지만, 경우에 따라서 leading edge에서도 실행되거나, 양쪽 모두에서 실행되기도 한다.

예를 들어서, Lodash나 es-toolkit에 구현된 debounce 함수는 인자로 leading, trailing같은 옵션을 주어서 어디에서 함수를 실행할 지 결정할 수 있다.

2.2.1. trailing=true

이 예시는 기본적인 디바운스 동작을 보여준다.

사용자가 입력을 빠르게 여러 번 발생시키더라도, 마지막 이벤트 발생 후 지정된 시간(여기에서는 300ms, 3 tick)이 지나야만 함수가 실행된다.

 

 

2.2.2. leading=true

이 예시는 입력 이벤트가 발생한 시점에 즉시 함수가 실행되고, 이후 일정 시간동안 이벤트가 발생해도 추가적인 실행이 발생하지 않는다.

마지막 호출에서 일정 시간이 지나 새로운 호출이 들어오면 함수가 다시 실행되는 방식이다.

 

 

2.2.3. leading=true; trailing=true

이 예시에서는 1. 이벤트가 시작될 때와 2. 마지막으로 멈췄을 때, 총 2번 실행된다.

(대신 함수가 총 1번만 호출되었다면 leading edge에서만 호출된다. 디바운싱된 함수를 leading edge에서 한 번 호출해서 원래 함수를 다시 호출할 수 없기 때문이다.)

 

 

3. 스로틀(Throttle)

스로틀(Throttle) 이란, 어떤 작업이 일정한 간격/비율로만 실행되도록 보장하는 방법이다.

즉, 아무리 호출을 많이 해도 일정 시간마다 최대 1번만 함수를 수행하게 된다.

3.1. 스로틀 예시: 화면 스크롤

사용자가 화면을 스크롤하는 상황을 생각해 보자.

이런 경우에 onScrolled 함수를 스로틀해서 일정 시간마다 한 번만 호출되도록 제한할 수 있다.

3.2. 스로틀 실행해보기

함수를 스로틀하면 이런 과정을 거쳐 함수 실행이 일어난다.

  1. onScrolled 호출이 일어난다. (이 호출을 leading edge라고 부른다)
  2. 다음으로 onScrolled 함수의 호출이 첫 호출(leading edge)로부터 일정 시간(ex. 10ms) 이내에 일어난다면, 이 호출은 첫 호출과 같은 batch에 있다고 판단하고, 실행하지 않는다.
  3. onScrolled의 첫 호출 이후로 일정 시간이 지났다면, trailing edge에 도달한 것이다.

보통 스로틀링된 함수는 leading edge에서만 실행되지만, 경우에 따라서 trailing edge에서도 실행되거나, 양쪽 모두에서 실행되기도 한다.

예를 들어서, Lodash나 es-toolkit에 구현된 throttle 함수는 인자로 leading, trailing같은 옵션을 주어서 어디에서 함수를 실행할 지 결정할 수 있다.

3.2.1. leading=true

이 예시는 기본적인 스로틀 동작을 보여준다.

사용자가 이벤트를 빠르게 여러 번 발생시켜도, 첫 번째 이벤트가 발생한 시점에만 함수가 실행된다. 이후 설정된 시간(300ms, 3 tick) 동안에는 추가 호출이 무시된다.

 

 

3.2.2. trailing=true

사용자가 입력을 빠르게 여러 번 발생시키더라도, 마지막 스로틀링된 함수 호출로부터 일정 시간(여기에서는 300ms, 3 tick)이 지나야만 함수가 실행된다.

 

 

3.2.3. leading=true; trailing=true

이 예시에서는 1. 이벤트가 시작될 때와 2. 마지막으로 멈췄을 때, 총 2번 실행된다.

(대신 함수가 총 1번만 호출되었다면 leading edge에서만 호출된다. 스로틀된 함수를 leading edge에서 한 번 호출해서 원래 함수를 다시 호출할 수 없기 때문이다.)

 

 

참고