본문으로 바로가기

Throttle, Debounce & Difference

스로틀(Throttle)디바운스(Debounce)란 무엇일까?






이 두 가지 방법 모두 DOM 이벤트를 기반으로 실행하는 자바스크립트를 성능상의 이유로 JS의 양적인 측면, 즉 이벤트(event)를 제어(제한)하는 방법입니다.

예를 들어, 웹/앱 사용자가 스크롤(scroll wheel), 트랙패드, 스크롤 막대를 드래깅 한다고 가정해 봅니다.
스크롤(scroll wheel), 트랙패드, 스크롤 막대를 드래깅을 하게 되면 사용자는 크게 느끼지 못할 수 있으나 이 행위로 인해 수많은 스크롤 이벤트가 발생하게 됩니다.
즉, 사용자가 아래로 5000픽셀 정도의 스크롤 다운을 한다면 100 개 이상의 이벤트가 발생될 가능성이 큽니다.
이러한 스크롤(scroll wheel), 트랙패드, 스크롤 막대를 드래깅함으로써 매번 스크롤 이벤트에 대한 콜백(callback)이 발생하고 그 콜백이 수행하는 일이 매우 큰 리소스를 잡아먹게 될 것입니다.
다시 말해, 과도한 이벤트 횟수의 실행으로 이벤트 핸들러가 무거운 계산 및 기타 DOM 조작과 같은 작업을 수없이 많이 수행하는 경우 성능 문제가 발생하고 이는 사용자 경험까지 떨어뜨리게 될 것입니다.


다음은 위에 설명드린 상황과 유사한 예제입니다.

See the Pen Scroll events counter by jaeheekim (@jaehee) on CodePen.


이러한 문제는 2011년에 트위터 웹 사이트에서 트위터를 스크롤 할 때 속도가 느려지고 응답이 없는 현상이 나타났습니다.
jQuery 창시자인 존 레식(John Resig)은 스크롤 이벤트에 값 비싼 기능을 직접 부착하는 것이 얼마나 나쁜 것인지에 대한 블로그 게시물을 게시했습니다.

당시에 존 레식이 제안안 해결책은 onScroll 이벤트 외부에서 일정 시간마다 250ms 씩 실행되는 루프였고, 그렇게하면 과도한 이벤트 처리가 되지 않습니다. 이 간단한 기술로 사용자 경험을 망치지 않을 수 있었습니다.

요즘에는 그 당시보다 이벤트를 처리하는 정교한 방법으로 사용되는 것이 Throttle, Debounce 이란 해결책입니다.
ThrottleDebounce이벤트 핸들러가 많은 연산(예 : 무거운 계산 및 기타 DOM 조작)을 수행(이벤트 핸들러의 과도한 횟수가 발생하는 것)하는 경우 에 대해 제약을 걸어 제어할 수 있는 수준으로 이벤트를 발생(그 핸들러를 더 적게 실행하면 빠져 나갈 수 있음)시키는 것을 목표 로 하는 기술입니다.


ThrottleDebounce 사용 사례

  • 사용자가 창 크기 조정을 멈출 때까지 기다렸다가 resizing event 사용하기 위해
  • 사용자가 키보드 입력을 중지(예: 검색창) 할 때까지 ajax 이벤트를 발생시키지 않기 위해
  • 페이지의 스크롤 위치를 측정하고 최대 50ms 마다 응답하기를 바랄 경우에
  • 앱에서 요소를 드래그 할 때 좋은 성능을 보장하기 위해

디바운스(debounce)와 스로틀(throttle)은 시간이 지남에 따라 함수를 몇 번이나 실행 할지를 제어하는 유사한 기술이지만 서로 다릅니다.

디바운스 또는 스로틀은 DOM 이벤트에 함수를 첨부 할 때 특히 유용합니다.
그 이유는 이벤트와 함수 실행 사이에 제어 계층을 제공하기 때문입니다. 그리고 기억해야 할 것은 DOM 이벤트가 얼마나 자주 내보내 질지는 제어하지 않는다는 것을 알아야 합니다.

해당 기술과 그 차이점에 대해 알아보도록 하겠습니다.



Debounce

Debounce 는 이벤트를 그룹화하여 특정시간이 지난 후 하나의 이벤트만 발생하도록 하는 기술입니다.
즉, 순차적 호출을 하나의 그룹으로 "그룹화"할 수 있습니다.

Debounce : 연이어 호출되는 함수들 중 마지막 함수(또는 제일 처음)만 호출하도록 하는 것



당신이 엘리베이터 안에 있다고 상상해 보세요. 문이 닫히기 시작하고 갑자기 다른 사람이 타려고 한다면 엘리베이터가 층으로 이동하는 기능을 시작하지 않아서 문이 다시 열리게 됩니다. 그리고 또 다른 사람에 의해 층의 이동 변경 기능이 일어나게 됩니다. 즉, 엘리베이터는 기능을 지연시키고 있지만(층간 이동), 자원을 최적화하게 됩니다.


단추를 클릭하거나 마우스 위로 움직여 디바운스의 예제를 확인해 보세요

See the Pen Debounce. Trailing by jaeheekim (@jaehee) on CodePen.

위 예제에서 연속적인 빠른 이벤트가 단일 디바운싱 이벤트로 어떻게 표현되는지 볼 수 있습니다.

그러나 이벤트가 큰 간격으로 발생되면 디바운싱은 발생하지 않습니다.



리사이즈 예제(Resize Example)

데스크탑의 브라우저 창 크기를 조정하는 경우에 많은 크기 창 조정 이벤트를 내보낼 수 있습니다.

다음은 브라우저 창 조정에 대한 데모입니다.

See the Pen Debounce Resize Event Example by jaeheekim (@jaehee) on CodePen.

보시다시피 resize 이벤트에 대해 마지막을 추적하고 있습니다.
왜냐하면 우리는 사용자가 브라우저 크기를 조정하지 않은 최종 값에만 관심이 있기 때문입니다.



Ajax 요청이있는 자동 완성 양식의 키 누르기 예제

요즘 서비스들은 검색어 치자마자 엔터 없이도 결과가 바로바로 나옵니다.
만약 '제로초'를 검색창에 친다고 합시다. 엔터 없이도 결과를 즉시 보여주려면 항상 input 이벤트에 대기하고 있어야 합니다.
문제는 한 글자 칠 때마다 ajax 요청이 실행된다는 것입니다. 'ㅈ', '제', '젤', '제로', '제롳', '제로초' 모두 요청이 실행됩니다.
6번이나 요청을 했습니다(한글같은 조합형 언어는 사진처럼 6번보다 더 많이 이벤트가 발생할 수도 있습니다). 거기에 'ㅈ', '젤', '제롳'는 제대로 된 검색 결과가 나오지 않을 것 같은 검색어입니다.

이와 같은 낭비는 유료 API를 사용했을 때 큰 문제가 됩니다.
만약 구글지도 API같은 것을 사용할 때 위와 같이 쿼리를 10번 날리면 어마어마한 손해입니다.
쿼리 하나가 다 돈이거든요. 따라서 디바운싱은 비용적인 문제와도 관련이 있습니다. 그렇기 때문에 마지막 '제로초'를 다 쳤을 때 ajax 요청을 보내야 할 것입니다.


다음은 위와 같은 유사한 예제입니다.

See the Pen Debouncing keystrokes Example by jaeheekim (@jaehee) on CodePen.





Throttle

Throttle 은 이벤트를 일정한 주기마다 발생하도록 하는 기술입니다.
예를 들어 Throttle 의 설정시간으로 1ms 를 주게되면 해당 이벤트는 1ms 동안 최대 한번만 발생하게 됩니다.

Throttle : 마지막 함수가 호출된 후 일정 시간이 지나기 전에 다시 호출되지 않도록 하는 것


특성 자체가 실행 횟수에 제한을 거는 것이기 때문에 일반적으로 성능 문제 때문에 많이 사용합니다.
스크롤을 올리거나 내릴 때 scroll 이벤트 핸들러 경우에 매우 많이 발생합니다.
scroll 이벤트가 발생할 때 뭔가 복잡한 작업을 하도록 설정했다면 매우 빈번하게 실행되기 때문에 큰 버퍼링이 걸릴 지도 모를 것입니다.
그럴 때 쓰로틀링을 사용할 수 있스빈다. 몇 초에 한 번, 또는 몇 밀리초에 한 번씩만 실행되게 제한을 두는 것입니다.



무한 스크롤링 페이지(Infinite scrolling page)

사용자가 footer 에서 얼마나 떨어져 있는지 확인해야하고 사용자가 맨 아래로 스크롤 했다면 Ajax 를 통해 더 많은 콘텐츠를 요청하여 페이지에 추가해야 합니다.

디바운싱은 사용자가 스크롤을 멈출 때만 이벤트를 발생시키므로 디바운싱보다는 스로틀이 적합할 수 있습니다. 사용자가 footer 에 도달하기 전에 콘텐츠를 가져와야 하기 때문입니다.
throttle 을 통해 사용자 위치가 얼마나 footer 로 부터 떨어져 있는지 항상 확인할 수 있습니다.

See the Pen Infinite scrolling throttled by jaeheekim (@jaehee) on CodePen.


애니메이션 프레임 예제

See the Pen Scroll comparison requestAnimationFrame vs throttle by jaeheekim (@jaehee) on CodePen.





Debounce 와 Throttle 차이점

디바운싱과 스로틀의 가장 큰 차이점은 스로틀은 적어도 X 밀리 초마다 정기적으로 기능 실행을 보장한다는 것입니다.
Debounce 는 아무리 많은 이벤트가 발생해도 모두 무시하고 특정 시간사이에 어떤 이벤트도 발생하지 않았을 때 딱 한번만 마지막 이벤트를 발생시키는 기법입니다.
따라서 5ms 가 지나기전에 계속 이벤트가 발생할 경우 콜백에 반응하는 이벤트는 발생하지 않고 계속 무시됩니다.


Debounce 와 Throttle 차이점 예제 간단히 살펴보기

See the Pen The Difference Between Throttling, Debouncing, and Neither by jaeheekim (@jaehee) on CodePen.





Jaehee's WebClub