연속적으로 들어오는 입력중에 처음이나 마지막 입력만 실행하게 하는 기법을 디바운싱
이라고 한다.
디바운싱도 어떤 시점을 입력하게 할건지에 따라서 trailing edge와 leading edge로 나눌수 있다.
연속적으로 들어오는 입력중에 마지막 입력만 실행하게 하는 기법이다.
연속적으로 들어오는 입력중에 처음의 입력만 실행하게 하는 기법이다.
const $input = document.querySelector("#input");
const $app = document.querySelector("#app");
const callAjaxRequest = (e) => {
$app.insertAdjacentHTML("beforeend", `<p>ajax 요청: ${e.target.value}</p>`);
};
const debounce = (func, wait, leading = false) => {
let timer; // closure를 사용하여 timer 변수 초기화
return (e) => {
let callNow = leading && !timer;
const later = () => {
timer = null;
if (!leading) {
func(e);
}
};
clearTimeout(timer);
timer = setTimeout(later, wait);
if (callNow) {
func(e);
}
};
};
$input.addEventListener("input", debounce(callAjaxRequest, 1000, true));
가장 처음에 closure를 이용하여 timer 변수를 선언합니다.
먼저 leading이 false인 trailing edge상황부터 보겠습니다.
leading이 false이기에 callNow는 무조건 false가 됩니다.
첫 실행을 하면 먼저 clearTimeout은 timer가 없기때문에 넘어간후 setTimeout
으로 later
를 wait
시간 뒤에 실행시켜줍니다.
이 wait가 돌아가는 동안의 실행을 알아보겠습니다. 이상태에서는 다시 clearTimeout을 실행시켜 현재 타이머를 초기화시킵니다. 그런후 다시 타이머를 wait만큼 실행합니다. 그래서 이 wait시간이 지나서 later를 실행하기전까지 입력을 계속하면 계속 타이머가 취소되고 wait만큼 입력이 없다면 그때 later를 실행합니다.
이번엔 leading이 true인 leading edge에 대해서 알아보겠습니다.
leading이 true이기에 callNow
는 timer에 따라서 false, true가 결정됩니다.
첫실행을 할 경우 timer
는 할당되어있지않기에 undefined이고 leading
이 true이기에 callNow
는 true가 됩니다. 그리고 trailing edge와 동일하겍 타이머는 실행이 됩니다. 그런후 callNow가 true이기 때문에 등록한 함수를 바로 실행을 합니다.
그렇다면 그 다음 입력부터는 어떻게 될까요?
timer가 존재하기에 callNow가 false가 됩니다. 그런후 setTimeout을 꺼버리고 다시 timer를 재설정합니다. 이번에는 callNow가 false이기에 함수를 실행하지않습니다.
이것이 계속 반복되기에 timer가 돌아가는 동안은 모든 입력을 무시합니다. 그리고 wait만큼의 시간이 지나면 timer = null로 초기화하기때문에 다시 입력을 받을수 있는 상태가 됩니다.
연속되는 입력에서 일정시간마다 한번만 입력될수 있도록 하는 프로그래밍 기법이다.
const throttle = (func) => {
let timer;
return () => {
if (!timer) {
timer = setTimeout(() => {
timer = null;
func();
}, 50);
}
};
};
$app.addEventListener("scroll", throttle(increaseCountNumber));
가장 처음에 closure를 이용하여 timer를 선언합니다. 첫 실행때 timer가 undefined이기에 if 문을 들어갑니다. 그런후 setTimeout을 실행합니다. 이 타이머는 50ms 후에 timer를 null로 초기화하고 함수를 실행합니다. 첫실행후 50ms동안은 timer가 존재하는 상태이기에 어떠한 입력도 무시합니다. 50ms후 함수를 실행하며 timer가 null이기에 다시 if문에 들어갈수있는 상태가 됩니다.
즉, 이런식으로 이용하면 50ms 마다 한번의 입력만 받게 하도록 하는 쓰로틀링의 코드가 완성됩니다.
둘다 입력을 제한한다는 점에서 유사해 보이지만 차이점이 있다.
일단 디바운싱은 주로 api통신을 할때 사용된다. 여러번 똑같은 요청을 하면 쓸모없는 api 호출이 불러와지기 때문에 처음 한번 혹은 마지막 한번만 하게 한다.
반면 쓰로틀링은 성능최적화할때 사용된다. 스크롤 이벤트에 비용이 큰 이벤트 핸들러가 걸려있다고 생각해보자. 스크롤 이벤트는 살짝만 내려도 수십개의 이벤트가 발생하는것을 볼수있다. 이런곳에 비용이 큰 이벤트핸들러가 걸려있다면 당연히 성능에 문제가 생길수 밖에 없을것이다. 그래서 사용하는것이 쓰로틀링이다.
그래서 디바운싱은 입력을 마치기전까지 내가 계속 입력을 하고있다면 무한히 그 입력이 무시되고 쓰로틀링은 반드시 지정한 시간내에 한번은 실행하도록 보장을 해준다.