[Javascript] Deboune / Throttle

Dongjun Ahn·2022년 12월 7일
0

일단 Debounce, Throttle 이 두가지 방법은 모두 DOM 이벤트를 기반으로 실행하는 JS를 성능상의 이유로 JS의 양적인 측면, 즉 이벤트를 제어하는 방법이다.
Throttle과 Debounce는 이벤트 핸들러가 많은 연산을 수행하는 경우에 대해 제약을 걸어 제어할 수 있는 수준으로 이벤트를 발생시키는 것을 목표로 하는 기술이다.

디바운스(Debounce)

Debounce 는 동일 이벤트가 반복적으로 시행되는 경우 특정시간이 지난 후 하나의 이벤트만 발생하도록 하는 기술이다.

연이어 호출되는 함수들 중 마지막 함수(또는 제일 처음)만 호출

const debounce = (callback) => {
    let timer = null;

    return (event) => {
        if(timer) clearTimeout(timer);
        timer = setTimeout(() => callback(event), 200);
    };
};

Input Envent Ajax요청

특정 단어를 검색창에 친다고할때 결과를 즉시보여주려면 항상 input 이벤트에 대기하고있어야한다. 문제는 한 글자 칠때마다 Ajax 요청이 실행된다는것이다. '안녕'을 친다하면 'ㅇ','아','안','안ㄴ','안녀','안녕' 6번 요청을한다. 이처럼 API를 과도하게 호출하게되면 비용적이나 성능적으로 문제가생긴다.
해결 방법은 입력이 다 끝난 후에 요청을 보내면 된다. 즉 타자를 칠 때(input 이벤트 발생)마다 타이머를 설정하고 200ms동안 입력이 없으면 입력이 끝난 것으로 친다(시간은 적당히 설정하면 됨). 200ms 이전에 타자 입력이 발생하면 이전 타이머는 취소하고 새로운 타이머를 다시 설정하는 방법이 디바운싱 이다.

var timer;
document.querySelector('#input').addEventListener('input', function(e) {
  if (timer) {
    clearTimeout(timer);
  }
  timer = setTimeout(function() {
    console.log('여기에 ajax 요청', e.target.value);
  }, 200);
});

쓰로틀(Throttle)

Throttling은 이벤트를 일정한 주기마다 발생하도록 하는 기술이다.
예를 들어 Throttle의 설정 시간으로 1ms를 주게 되면 해당 이벤트는 1ms 동안 최대 한번만 발생하게 된다. (너무 짜잘한 값에 대해 일일이 반응할시에 발생하는 성능 저하를 막기 위해 사용)

마지막 함수가 호출된 후 일정 시간이 지나기 전에 다시 호출되지 않도록 하는 것

특성 자체가 실행 횟수에 제한을 거는 것이기 때문에 일반적으로 성능 문제 때문에 많이 사용한다.

const throttle = (callback) => {
    let timer;

    return (event) => {
        if(!timer) {
            timer = setTimeout(() => {
                timer = null;
                callback(event);
            }, 200);
        }
    };
};

무한 스크롤링 페이지(Infinite scrolling page)

디바운싱은 사용자가 스크롤링을 멈출 때만 이벤트를 발생시키므로 Debounce 보다는 scroll을 하고 있는 동안에는 300ms씩 마다 이벤트 핸들러가 호출이되어서 scroll event 핸들러의 호출 빈도를 줄일 수 있는 throttle이 적합할 수 있다. 사용자가 footer에 도달하기 전에 콘텐츠를 가져와야 하기 때문이다.
즉, throttle을 통해 사용자 위치가 얼마나 footer로 부터 떨어져 있는지 항상 확인할 수 있다.

Typescript Debouce/Throttle

type timer = number | null;
export const debounce = <F extends (...args: any[]) => any>(func: F, wait: number) => {
	//   let timeout: ReturnType<typeof setTimeout> | null = null;

	let timeout: timer = null;
	const debounced = (...args: Parameters<F>) => {
		if (timeout !== null) {
			clearTimeout(timeout);
			timeout = null;
		}
		timeout = setTimeout(() => func(...args), wait);
	};

	return debounced as (...args: Parameters<F>) => ReturnType<F>;
};

export const throttle = <F extends (...args: any[]) => any>(func: F, waitFor: number) => {
	let throttleCheck: timer;
	const throttled = (...args: Parameters<F>) => {
		if (!throttleCheck) {
			throttleCheck = setTimeout(() => {
				func(...args);
				throttleCheck = null;
			}, waitFor);
		}
		return throttled as (...args: Parameters<F>) => ReturnType<F>;
	};
};
profile
Front-end Developer

0개의 댓글