본문 바로가기
Web/JavaScript

[JS] 디바운싱(Debouncing)과 쓰로틀링(Throttling)

by 서상혁 2021. 6. 5.

디바운싱(Debouncing)과 쓰로틀링(Throttling)

디바운싱(Debouncing)과 쓰로틀링(Throttling) 은 사실, 자바스크립트의 개념이라기 보다는 프로그래밍 기법중 하나입니다. 둘 다 디바이스(일반적으로 CPU)의 무리를 주지 않기 위해 사용되곤 합니다. 일종의 최적화라고 볼 수 있습니다. 그렇다면 디바운싱과 쓰로틀링이 각각 무엇을 의미하는지 알아보시죠!

  • 디바운싱(Debouncing) : 연이어 발생한 이벤트를 하나의 그룹으로 묶어서 처리하는 방식으로, 주로 그룹에서 마지막, 혹은 처음에 처리된 함수를 처리하는 방식으로 사용되곤 한다.
  • 쓰로틀링(Throttling) : 연이어 발생한 이벤트에 대해, 일정한 delay를 포함시켜 연속적으로 발생한 이벤트는 무시하는 방식을 뜻한다. 즉, delay 시간동안 호출된 함수는 무시하는 케이스 이다.

언어적 의미

저는 원체 단어나 단순 암기를 못하는 편이라, 새로운 것을 배울 때는 스토리 위주로 생각해서 암기하곤 합니다. 그런 의미에서 Debouncing 과 Throttling을 사전에 검색해보았습니다. 📖

Debouncing :

저는 처음에 Debouncing이 debounce라는 동사의 명사형태 인줄 알았습니다. 허나, debounce 는 사전에 등재된 단어는 아닙니다. Debouncing만이 컴퓨터 사이언스 용어로 등재되어 있습니다. 검색해보니, 전자 쪽에서 bouncing 이라는 용어가 있습니다. 스위치들이 접점에서 떨어지거나 붙는 시점에 물리적으로 미세하게 여러번의 on/off 가 되는 현상을 뜻합니다. bounce 의 튀는 의미를 담은 것 같아요. 이는 의도했던 바가 아니니, 방지하는게 좋겠죠? 그런 의미에서 이런 불필요한 튀는 현상,( 여러 on/off 발생)을 방지하는 의미에서 debouncing이라고 표현한 것 같습니다. 앞서 말씀드린 '여러 이벤트가 발생할 때, 일정 그룹으로 묶어서 하나로 처리' 하는 debouncing의 의미와 일맥상통하죠!

Throttling :

Throttle
1.
목을 조르다; 목을 졸라 죽이다
2.
(자동차 등의 연료) 조절판

목을 조르다(... ???)
throttle 이라는 단어는 다소 무서운 의미를 가지고 있는데요. 이것 외에도 쓰이는 의미를 보면, 보통 무언가를 '조이거나 조르는' 의미를 담고 있습니다. throttling은 들어보셨을지 모르겠지만, '압력 조절' 이라는 뜻을 가지고 있습니다. 저는 수도꼭지에서 물이 나오는데, 그것을 조여서 압력을 조절하는 이미지를 상상하곤 합니다. 자바스크립트, 혹은 컴퓨터 사이언스에서도 마찬가지의 의미를 담고있습니다. 요청, 혹은 이벤트가 의도한 바 보다 너무 과도하게 발생할 때, 일정 delay를 주고, delay동안은 수도꼭지를 조여버리는 것입니다. 그 기간동안 발생한 이벤트, 요청, 함수 등은 무시가 되는 것이죠!

이처럼 용어 자체의 맥락이나 의미를 바탕으로 이해하면 더 오래 기억에 남을 것이라 생각합니다 ㅎㅎ


예시



역시 백번 글로 쓰는 것 보다 , 한번 직접 예시를 보는게 제일 이해가 빠르죠!
거두절미하고 바로 예시로 넘어가 보겠습니다.

예시 코드를 위해 기본적인 html 템플릿을 만들어보았습니다.
js 윈도우 객체에 스크롤 이벤트를 담아, 스크롤 이벤트가 발생할 때 마다 count를 올리고 로그를 찍게끔 구현했습니다.

기본 템플릿

<!DOCTYPE html> <html> <body> <div id="main" style="height: 300vh;"> <h2>Throttling & Debouncing</h2> <div style="display: flex; flex-direction: column; position: fixed;"> <h3>아무 처리도 하지 않았을 때</h3> <div> <label>이벤트 발생 : </label> <span id='count'>0</span> </div> </div> </div> </body> <script> window.addEventListener('scroll', function (e) { console.log('스크롤 이벤트 발생!'); const count = document.getElementById('count'); count.innerText = parseInt(count.innerText) + 1 }) </script> </html>
스크롤 이벤트

스크롤 이벤트가 발생하는 모든 순간마다, 함수가 호출되고 count가 늘어납니다.
스크롤은 조금밖에 하지 않았지만 count 값이 매우 급격하게 늘어나는 것을 볼 수 있죠.
지금은 단순히 로그만을 찍고 count를 늘리는 함수지만, 이 함수가 좀 더 무거운 작업을 하는 경우라거나, 스크롤을 할 때마다 레이아웃 렌더링이 되는 경우는 성능 상의 이슈가 생길 수도 있겠죠. 😅


디바운싱 적용

<!DOCTYPE html> ... <script> var debouncer window.addEventListener('scroll', function (e) { if (debouncer) { clearTimeout(debouncer); } debouncer = setTimeout(function() { console.log('스크롤 이벤트 발생!'); const count = document.getElementById('count'); count.innerText = parseInt(count.innerText) + 1 }, 300); }) </script> </html>
디바운싱 적용


만약 이벤트가 이전 이벤트가 끝나고 300ms 보다 빠르게 발생한 경우, 이전 이벤트에 기록된 디바운서를 지우고 다시 디바운서를 킵니다. 결과적으로 마지막으로 발생한 이벤트에 대해서만 300ms 가 지난 후 이벤트 콜백 함수가 호출되게 됩니다!



쓰로틀링 적용

<!DOCTYPE html> ... <script> var throttler window.addEventListener('scroll', function (e) { if (throttler) { return } throttler = setTimeout(function() { console.log('스크롤 이벤트 발생!'); const count = document.getElementById('count'); count.innerText = parseInt(count.innerText) + 1 throttler = null; }, 200); }) </script> </html>


쓰로틀러를 200ms동안 작동시키고, 만약 쓰로틀러가 이벤트를 조이고 있는 경우, 해당 이벤트는 무시됩니다. 결과적으로 200ms 동안 최대 1번의 이벤트만이 발생이 가능하게 됩니다!


마치며


자바스크립트는 이벤트 기반의 언어이기도 하고, 브라우저 환경에서 렌더링은 성능을 크게 좌지우지 하기 때문에, 이런 쓰로틀링과 디바운싱의 개념이 중요하게 여겨지는 것 같습니다. 최근 리액트에서 실험중인 Concurrent 모드 또한, 이런 어플리케이션 단에서의 디바운싱과 쓰로틀링 구현의 필요성을 줄이기 위하는 데에도 일조하고 있는 것이라고 하죠. 최적화의 방법은 정말 무궁무진하고 그 만큼 많은 생각을 해야된다는 것을 느낍니다. 쓰로틀링과 디바운싱의 이벤트지연을 통한 최적화 없이도 브라우저가 충분히 빠르게 작동할 수 있는 날이 오겠죠? 하지만 지금으로서는 반드시 알고있어야 할 개념으로 보입니다 ㅎㅎ 이만 마칩니다!




728x90

댓글