자바스크립트 개발에 있어서 이벤트는 빠질 수 없는 요소입니다. 과장을 보태 자바스크립트 개발을 해 본 개발자 중에 이벤트 처리를 해 보지 않은 개발자는 없다고 말해도 과언이 아닐 것입니다. 디바운스(Debounce)와 스로틀(Throttle)은 이러한 이벤트를 제어하는 방법으로, 과도한 이벤트의 발생이 성능 저하를 초래하지 않도록 하기 위해 사용합니다.
대표적으로 디바운스와 스로틀을 이용하여 이벤트 발생을 제어하는 기능은 아래와 같습니다.
- 스크롤 휠을 이용한 지도 확대/축소
- 검색어 입력시 자동완성 혹은 연관검색어 노출
- 피드 방식의 데이터 노출 (스크롤링을 통한 데이터 노출)
이벤트 오버클럭(Overclock - 과도한 이벤트 발생)은 리소스 사용량을 과도하게 증가시키기 때문에 성능 문제를 야기하고 사용자 경험을 떨어뜨립니다. 특히 스크롤 이벤트의 경우 이벤트 오버클럭을 발생시키기 쉬운데, 이는 사용자가 스크롤을 빨리 내리면 3초의 간격 내에 몇 천 번 이상의 이벤트가 발생할 수 있기 때문입니다. 오래전 이야기지만, 실제로 트위터가 디바운스나 스로틀을 이용하지 않고 스크롤 이벤트를 통해 웹페이지 하단에 피드를 붙이도록 구현하였다가, 화면이 매우 느려지고 무반응 상태가 되는 문제가 발생하였습니다. 따라서 디바운스와 스로틀을 알아두는 것이 좋습니다.
디바운스와 스로틀은 특정 함수 그룹을 시간 간격을 두어 호출하면서 실행하여 과도한 이벤트 발생을 막는다는 점에서는 유사하나, 서로 다르게 동작합니다.
(1) 디바운스(Debounce) 란?
디바운스는 이벤트를 그룹화(Grouping)하여, 연이어 호출되는 함수들 중 마지막 함수만 호출하도록 하는 기술입니다.
위 그림에서 1, 7, 8의 이벤트가 실행되는 것을 볼 수 있는데, 디바운스에 지정한 delay time 동안 사용자가 이벤트를 발생시키지 않았기 때문입니다. delay time보다 짧은 시간 내에 이벤트가 발생한 2, 3, 4, 5, 6 은 이벤트가 발생하지 않으며, 이것이 바로 디바운스의 특징입니다.
Ajax로 처리되는 입력에 따른 자동완성/연관검색어 노출이 대표적인 디바운스의 예시입니다.
(2) 스로틀(Throttle) 이란?
스로틀은 일정 시간 내에 한 번만 함수를 호출하도록 하는 기술로, 디바운스와 가장 큰 차이점이라면 정해진 시간 간격 내에 반드시 최대 한 번 함수가 호출된다는 것입니다.
디바운스와 달리 스로틀은 사용자가 이벤트를 일으킨 점선 박스 시간 동안 기다렸다가, 가장 마지막에 호출된 이벤트를 발생시킵니다. 그래서 디바운스와 달리 1, 4, 7, 8의 이벤트가 발생하게 되는 것입니다.
스로틀은 스크롤 이벤트를 제어할 때 많이 사용됩니다. (구현에 따라 스크롤 이벤트 제어에 디바운스를 사용할 수도 있고, 마찬가지로 자동완성 기능에 스로틀을 사용할 수도 있습니다)
(3) 예제
디바운스와 스로틀은 이름은 생소할 수 있을지 모르나, 알고 보면 많은 이벤트 처리에 사용되는 기술입니다. 그리고 실제로 나도 모르게 사용하고 있었을 수도 있을 만큼, 그렇게 어려운 개념은 아닙니다. 예제와 함께 좀 더 자세히 알아보도록 하겠습니다.
<input type="text" id="searchBox"/>
<br>
<div>
<ul id="keywordRecommendArea">
</ul>
</div>
위와 같이 사용자의 입력을 받는 searchBox라는 input 창과, 사용자의 입력에 따라 자동완성 데이터를 노출할 keywordRecommendArea라는 ul을 가진 div가 있다고 가정합니다. input 필드에 keyup 이벤트를 걸어, 입력된 값에 따른 자동완성 데이터를 ul에 li로 추가해 주는 코드를 작성해 보겠습니다.
간단한 테스트를 위한 코드이기 때문에, 별도로 서버를 작성하지 않고, 전역 변수로 keywords라는 배열을 만들어 이 데이터를 조회하도록 작성하겠습니다.
var keywords = ['key','keyword','kotlin','kiwi'];
$(function(){
$('#searchBox').on('keyup', debounce(callbackFn,500));
$(document).on('click', 'a', function(){
$('#searchBox').val($(this).html());
})
});
function callbackFn() {
const that = this;
$('#keywordRecommendArea').empty();
const recoms = keywords.filter(function(item){
return item.includes(that.value);
});
for(let recom of recoms){
$('#keywordRecommendArea').append('<li><a href="javascript:;" id="autoCompletion">'+recom+'</a></li>')
}
}
코드에서 보이듯 searchBox에 debounce 함수가 keyup 이벤트의 콜백 함수로 등록되어 있습니다. 여기서 사용하는 디바운스 코드는 아래와 같습니다.
function debounce(fn, delay) {
let timer;
return function(){
clearTimeout(timer);
timer = setTimeout(()=>{
fn.apply(this);
}, delay);
}
}
디바운스를 사용하여 테스트하면 아래와 같이 실행됩니다.
사용자의 입력이 멈추거나 500 ms 이상 느려지기 전까지는 자동완성 추천이 나타나지 않습니다.
그렇다면 콜백 함수로 디바운스 대신 스로틀을 넣어 보겠습니다.
function throttle(fn, delay) {
let timer;
return function(){
if(!timer) {
timer = setTimeout(()=>{
timer = null;
fn.apply(this,arguments)
}, delay)
}
}
}
이 결과는 아래와 같습니다.
디바운스와는 달리 입력이 진행 중임에도 자동완성 추천이 나타나는 것을 확인할 수 있습니다.
예제로 살펴보니, 이름이 다소 생소할 뿐 코드가 그리 어렵지 않습니다. 이렇게 직접 구현하여 사용할 수도 있지만, jquery의 경우 플러그인의 형태로 디바운스와 스로틀 기능을 제공하고 있습니다. 이외에도, lodash나 underscore와 같은 라이브러리에서도 내장함수로 구현되어 있기 때문에, 이를 이용하면 간편하게 함수 호출만으로도 동일한 기능을 수행할 수 있습니다.
[references]
Debouncing and Throttling Explained Through Examples
3 JavaScript questions to watch out for during coding interviews
'Javascript' 카테고리의 다른 글
Prototype Chain (0) | 2020.11.15 |
---|---|
Prototype (0) | 2020.11.15 |
[Javascript] 자바스크립트에서 메모리 누수의 4가지 형태 (0) | 2020.10.21 |
[Javascript] Closure (0) | 2020.10.21 |
[Javascript] 실행 컨텍스트 (0) | 2020.10.21 |
댓글