Code

[lodash/underscore] throttle과 debounce

April 24, 2016

[lodash/underscore] throttle과 debounce

throttle

매 밀리세컨드마다 최대 한 번만 호출될 수 있도록 Throttle된 함수를 만듭니다.

throttle by lodash

throttle – lodash
throttle – underscore

DOM API 중 onmousemove, onmouseover, onscroll 같은 이벤트는 1초 안에도 수 십 번씩 과다하게 호출될 수 있다. 이런 이벤트에 무거운 로직을 끼워두면 당연히 웹페이지의 성능이 떨어질 수 밖에 없다. 따라서 로직이 적당히 호출될 수 있도록 조절하는 작업이 필요한데, 이 때 간편하게 사용할 수 있는 것이 _.throttle이다.

_.throttle은 로직 실행 주기를 만드는 함수라고 이해하면 된다. 밀리세컨드 단위로 시간을 설정하면 _.throttle에 넘긴 콜백함수는 설정한 시간 동안 최대 한 번만 호출된다.

다음 예제를 보면 이해가 빠를 것이다.

위에서는 _.throttle 함수를 100 밀리세컨드 단위로 설정했다. 마우스를 올려놓고 움직여보면 throttle된 함수와 안된 함수의 차이가 드러나는 것을 볼 수 있다. 실제로 100~200 밀리세컨드 정도의 throttle은 throttle을 적용하지 않았을 때에 비해서 UX적인 차이가 크게 드러나지 않아 부담없이 적용할 수 있는 편이다.

_.throttle을 사용할 만한 실제 사례는 Infinite scroll을 생각해 볼 수 있겠다. Infinite scroll에서는 대개 AJAX 요청을 보내게 될 텐데, onscroll에 AJAX 요청을 바인딩해놓으면 스크롤 이벤트가 많이 일어나므로 과다한 요청을 보내게 된다. 당연하지만 이런 요청은 클라이언트와 서버, 모두 부담되기 때문에 적당한 양의 요청을 보내도록 조절해야 한다. 딱 _.throttle을 사용하기에 적당한 상황이다. 다음은 실제로 AJAX 요청을 보내지는 않지만 Infinite scroll을 구현한 예제이다.

debounce

마지막 호출 이후 일정 밀리세컨드 이후로 지연된 호출을 하도록 debounce된 함수를 만듭니다.

debounce by lodash

debounce – lodash
debounce – underscore

_.debounce_.throttle과 마찬가지로 과다한 이벤트 로직 실행을 방지하기 위해 사용되는 함수이다. 바로 실행되는 _.throttle과는 달리 호출이 반복되는 동안에는 로직 실행을 방지하며, 호출이 멈춘 뒤, 설정한 시간이 지나고 나서야 로직을 실행하게 된다.

이번에도 마우스를 올려놓고 움직여보면 어떤 식인지 쉽게 감이 올 것이다. _.debounce는 100 밀리세컨드로 설정되었다. 즉, 마우스를 멈춘 뒤 100 밀리세컨드가 지나면 카운트가 오른다.

_.debounce 역시 실제로 자주 활용되는데, 가장 자주 활용되는 사례로는 AJAX 요청을 이용하는 검색 인터페이스(Autocomplete)가 있겠다. 검색을 담당하는 input 요소에 무언가를 타이핑 할 때마다 AJAX 요청을 보내는 것은 마찬가지로 과도한 부담이다. 따라서 유저가 타이핑을 마쳤다고 예상되는 지점에서 요청을 보내는 것이 적당하다. 그럴 때 _.debounce를 사용해서 유저가 타이핑을 멈춘 뒤, 몇 밀리세컨드 이후에 요청을 보내면 되는 것이다.

마찬가지로 진짜 AJAX 요청을 보내고 있지는 않지만 debounce된 함수를 사용하는 예제이다. 이런 식의 검색 인터페이스는 이미 많은 곳에서 채택되었다. 대표적으로 페이스북. 실제로 검색해보면 타이핑하는 동안에는 검색결과가 노출되지 않는데 타이핑을 멈춘 뒤 약간 시간이 지나야 검색이 실행되는 모습을 볼 수 있다. 물론 클라이언트에 저장된 정보는 바로 검색된다. 이 경우에는 AJAX 요청만 debounce된 것이라고 볼 수 있겠다. (물론 페이스북이 lodash나 underscore를 쓰는지는 모르겠지만..)

마치며

얼마 전에 debounce된 AJAX 요청을 구현해야 할 일이 있었는데, 그 땐 이런 함수가 있다는 것 조차 몰랐기 때문에, 한참 헤메다가 setTimeout과 Promise를 이용해서 얼기설기 구현했던 기억이 난다. 이 포스트가 그렇게 헤메고 있는 사람들에게 도움이 되었으면 한다.

참고링크