발행일

[ZBF]7주차 보충 : debounce와 throttle의 개념

[ZBF]7주차 보충 : debounce와 throttle의 개념

이 글은 네이버 블로그에 2024년 6월 30일에 올렸던 것을 그대로 옮겨온 것입니다.

debounce와 throttle은 짧은 시간 동안 빈번하게 발생하는 이벤트의 처리를 제어하여 성능을 최적화하는 기술입니다.

  • Debounce: 연이어 발생하는 이벤트 중 마지막 이벤트만을 처리합니다. 예를 들어, 키보드 입력 이벤트에서 debounce를 사용하면 사용자가 입력을 멈추고 일정 시간이 지난 후에만 이벤트가 처리됩니다.
  • Throttle: 일정 간격으로 이벤트를 처리합니다. 예를 들어, 스크롤 이벤트에서 throttle을 사용하면 지정한 간격으로 이벤트가 발생하여 과도한 이벤트 처리를 방지합니다.

차이점

  • Debounce: 마지막 이벤트만 처리합니다.
  • Throttle: 처음 이벤트가 발생한 후 일정 간격으로 이벤트를 처리합니다.

웹 성능 최적화

예시: 키보드 입력 이벤트

  • Debounce: 사용자가 입력할 때마다 API 호출이 발생하면 성능 저하가 발생할 수 있습니다. debounce를 사용하면 사용자가 입력을 멈추고 일정 시간이 지난 후에 API 호출이 발생하여 불필요한 호출을 줄일 수 있습니다.
function debounce(func, delay) {
    let debounceTimer;
    return function() {
        const context = this;
        const args = arguments;
        clearTimeout(debounceTimer);
        debounceTimer = setTimeout(() => func.apply(context, args), delay);
    }
}

예시: 스크롤 이벤트

  • Throttle: 스크롤 이벤트가 빈번하게 발생하면 성능 저하가 발생할 수 있습니다. throttle을 사용하면 일정 간격으로 이벤트를 처리하여 성능을 최적화할 수 있습니다.
function throttle(func, limit) {
    let lastFunc;
    let lastRan;
    return function() {
        const context = this;
        const args = arguments;
        if (!lastRan) {
            func.apply(context, args);
            lastRan = Date.now();
        } else {
            clearTimeout(lastFunc);
            lastFunc = setTimeout(function() {
                if ((Date.now() - lastRan) >= limit) {
                    func.apply(context, args);
                    lastRan = Date.now();
                }
            }, limit - (Date.now() - lastRan));
        }
    }
}

키보드 입력 이벤트: 자동완성 검색 기능을 구현할 때, 사용자가 입력할 때마다 API 요청이 발생하여 서버에 과도한 부하가 걸리는 문제가 있었습니다. 이를 해결하기 위해 debounce를 사용했습니다.

장점: 불필요한 API 호출을 줄여 서버 부하를 줄일 수 있었습니다.

단점: 입력 후 일정 시간 동안 대기해야 결과가 나타나므로 사용자 경험이 약간 지연될 수 있습니다.

스크롤 이벤트: 웹페이지에서 무한 스크롤 기능을 구현할 때, 스크롤 이벤트가 너무 자주 발생하여 브라우저의 렌더링 성능이 저하되는 문제가 있었습니다. 이를 해결하기 위해 throttle을 사용했습니다.

장점: 이벤트 처리 빈도를 줄여 브라우저 렌더링 성능을 개선할 수 있었습니다.

단점: 첫 번째 이벤트와 그 이후 이벤트 사이의 간격 동안에 발생한 이벤트가 무시될 수 있습니다.

// Debounce function
function debounce(func, delay) {
    let debounceTimer;
    return function() {
        const context = this;
        const args = arguments;
        clearTimeout(debounceTimer);
        debounceTimer = setTimeout(() => func.apply(context, args), delay);
    }
}

// Throttle function
function throttle(func, limit) {
    let lastFunc;
    let lastRan;
    return function() {
        const context = this;
        const args = arguments;
        if (!lastRan) {
            func.apply(context, args);
            lastRan = Date.now();
        } else {
            clearTimeout(lastFunc);
            lastFunc = setTimeout(function() {
                if ((Date.now() - lastRan) >= limit) {
                    func.apply(context, args);
                    lastRan = Date.now();
                }
            }, limit - (Date.now() - lastRan));
        }
    }
}

// Usage examples
const handleInputChange = debounce((event) => {
    // API call
    console.log('API call with:', event.target.value);
}, 500);

const handleScroll = throttle(() => {
    console.log('Scroll event handled');
}, 200);

document.getElementById('inputField').addEventListener('input', handleInputChange);
window.addEventListener('scroll', handleScroll);