개념:
디바운스(debounce): 고주파 이벤트가 발생한 후 n초 동안 함수는 단 한 번만 실행됩니다. n초 내에 고주파 이벤트가 다시 발생하면 시간이 재설정됩니다.
스로틀(throttle): 고주파 이벤트가 발생하지만 n초 동안 함수는 단 한 번만 실행됩니다. 따라서 스로틀은 함수의 실행 빈도를 줄입니다.
디바운스와 스로틀 모두 함수의 실행 빈도를 제한하여, 과도한 트리거로 인해 발생할 수 있는 지연, 가짜 데드락 또는 프로그램 정지 현상을 방지하는 데 사용됩니다.
디바운스:
- 구현 방법: 이벤트가 발생할 때마다 지연된 호출 메서드를 설정하고 이전의 지연된 호출을 취소합니다.
- 단점: 지정된 시간 간격 내에 이벤트가 계속해서 트리거되면 호출이 지속적으로 지연될 수 있습니다.
/*
1. 디바운스: 이벤트가 발생할 때마다 지연된 호출을 설정하고 이전의 지연 호출을 취소합니다.
단점: 지정된 시간 안에 이벤트가 계속해서 발생하면 호출이 지속적으로 지연됩니다.
*/
function debounce(fn, wait) {
let timerId = null;
return function (...args) {
const context = this;
if (timerId !== null) {
clearTimeout(timerId);
}
timerId = setTimeout(() => {
fn.apply(context, args);
}, wait);
};
}
// 예제 함수
function logRandom() {
console.log('디바운스:', Math.random());
}
// 클릭 이벤트 처리
window.addEventListener('click', debounce(logRandom, 500));
스로틀:
- 구현 방법: 타임스탬프와 타이머를 사용합니다.
// 타임스탬프 기반 스로틀
function throttleByTimestamp(fn, limit) {
let lastCallTime = 0;
return function (...args) {
const now = Date.now();
const context = this;
if (now - lastCallTime >= limit) {
fn.apply(context, args);
lastCallTime = now;
}
};
}
// 타이머 기반 스로틀
function throttleByTimer(fn, limit) {
let timeoutId = null;
return function (...args) {
const context = this;
if (!timeoutId) {
timeoutId = setTimeout(() => {
fn.apply(context, args);
timeoutId = null;
}, limit);
}
};
}
// 타임스탬프와 타이머를 결합한 스로틀
function combinedThrottle(fn, limit) {
let timeoutId = null;
let lastExecutionTime = 0;
return function (...args) {
const now = Date.now();
const remainingTime = limit - (now - lastExecutionTime);
const context = this;
if (remainingTime <= 0) {
fn.apply(context, args);
lastExecutionTime = now;
} else if (!timeoutId) {
timeoutId = setTimeout(() => {
fn.apply(context, args);
lastExecutionTime = now + remainingTime;
timeoutId = null;
}, remainingTime);
}
};
}
// 예제 함수
function greet() {
console.log('스로틀:', Math.abs(22.22));
}
// 클릭 이벤트 처리
window.addEventListener('click', throttleByTimestamp(greet, 1000));
결론:
디바운스: 여러 번의 연속적인 작업을 하나의 작업으로 합칩니다. 기본 원리는 지연 타이머를 유지하며, 지정된 시간 이후에 함수를 실행하지만, 해당 시간 내에 다시 트리거되는 경우 이전 타이머를 취소하고 새로 설정합니다.
스로틀: 특정 시간 동안 함수가 단 한 번만 실행되도록 합니다. 기본 원리는 지연된 호출이 아직 실행 중인지 확인하는 것입니다.
차이점: 스로틀은 이벤트가 얼마나 자주 발생하든 상관없이 반드시 지정된 시간 내에 최소 한 번은 실제 이벤트 핸들러를 실행합니다. 반면, 디바운스는 마지막 이벤트 이후에 단 한 번만 함수를 실행합니다. 예를 들어, 페이지 스크롤 중 일정 시간마다 AJAX 요청을 보내야 하는 무한 스크롤 시나리오에서는 스로틀이 더 적합합니다.