Throttling & Debouncing
Throttling
- 짧은 시간 간격으로 연속해서 발생한 이벤트들을 일정시간 단위(delay)로 그룹화하여 처음 또는 마지막 이벤트 핸들러만 호출되도록 하는 것
ex) 무한스크롤
Debouncing
- 짧은 시간 간격으로 연속해서 이벤트가 발생하면 이벤트 핸들러를 호출하지 않다가 마지막 이벤트로부터 일정 시간(delay)이 경과한 후에 한 번만 호출하도록 하는 것
ex) 입력값 실시간 검색, 화면 resize 이벤트
메모리 누수(Memory Leak)
- 필요하지 않은 메모리를 계속 점유하고 있는 현상
- setTimeout 이 메모리 누수(
Memory Leak
)를 유발하는 지?
- 상황에 따라 메모리 누수를 일으킬 수도 있고 아닐 수도 있다.
- 하나의 페이지에서 페이지 이동 없이 setTimeout을 동작시키고 타이머 함수가 종료될 때까지 기다린다면 메모리 누수는 없다.
- 리액트로 만든 SPA 웹사이트는 페이지 이동 시 컴포넌트가 언마운트 됩니다.
- 그런데 페이지 이동 전에 setTimeout 으로 인해 타이머가 동작중인 상태에서 clearTimeout을 안해주고 페이지 이동 시 컴포넌트는 언마운트 되었음에도 불구하고 타이머는 여전히 메모리를 차지하고 동작하고 있다. 이 경우 메모리 누수(Memory Leak)에 해당한다고 말할 수 있다.
import { useEffect, useState } from "react";
type ControlDelay = (delay: number) => void;
export default function App() {
let timer: NodeJS.Timeout | null = null;
const throttle: ControlDelay = (delay) => {
if (timer) {
return;
}
console.log(`${(delay/1000).toFixed(1)}초 동안 추가요청 안받음`);
timer = setTimeout(() => {
console.log(`${(delay/1000).toFixed(1)}초 지남 추가요청 받음`);
timer = null;
}, delay);
};
const debounce: ControlDelay = (delay) => {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
console.log(`마지막 요청으로부터 ${(delay/1000).toFixed(1)}초 지났으므로 실행`);
timer = null;
}, delay);
};
useEffect(() => {
return () => {
if (timer) {
clearTimeout(timer);
}
};
}, [timer]);
return (
<div>
<button onClick={() => throttle(1000)}>쓰로틀링</button>
<button onClick={() => debounce(1000)}>디바운싱</button>
</div>
);
}
export default App;
✅ 체크 리스트
- Throttling 이 무엇인지 설명할 수 있다.
- 서버에 많은 요청을 주지 않기 위해 처음이나 마지막 이벤트 아니면 처음과 마지막 이벤트가 발생하였을 때에만 함수를 실행한다.
- Debouncing 이 무엇인지 설명할 수 있다.
- 연속적으로 이벤트가 발생하면 호출하지 않다가 마지막 이벤트에만 호출되는 것
- lodash 를 이용하여 쓰로틀링과 디바운싱을 적용할 수 있다.
- 리액트에서 Throttling/Debouncing 시 useCallback을 적용하는 이유를 설명할 수 있다.
- useCallback을 사용하는 이유는 이전에 호출했던 함수를 반복적으로 호출할 수 있게 하기 위해서이다.