본문으로 바로가기

Throttle, Debounce & Difference

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






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

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


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


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

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

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


ThrottleDebounce 사용 사례

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

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

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

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



Debounce

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

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



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


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

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

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



리사이즈 예제(Resize Example)

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

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

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



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

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

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


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





Throttle

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

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


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



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

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

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


애니메이션 프레임 예제





Debounce 와 Throttle 차이점

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


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





Jaehee's WebClub