JavaScript에서 debounce(디바운스)는
유저가 입력할 때마다 코드를 오직 한 번씩만 실행되도록 해주는 함수
검색 박스의 제안, 텍스트 필드의 자동 저장, 버튼의 더블 클릭의 제거가 모두 debounce를 이용하는 사례
출처와 예시 설명
사용 예시
타이핑을 끝내고 난 뒤에만 검색 질의(query)에 대한 제안 옵션을 보여주고 싶을 때 사용
코드 이해하기
#HTML
<html>
<head>
<title>JS leading debounce</title>
<link href="https://fonts.googleapis.com/css2?family=Jua&family=Roboto:wght@300&display=swap" rel="stylesheet">
<link rel="stylesheet" href="./assets/css/main.css">
</head>
<body>
<main>
<div class="card blue">
<h1>JS leading debounce</h1>
<input type="text" onkeyup="processChanges()" />
<button onclick="processChanges()">Click me</button>
</div>
</main>
</body>
</html>
# JavaScript
function debounce(func, timeout = 300) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, timeout);
};
}
function saveInput() {
console.log('Saving data');
}
const processChange = debounce(() => saveInput());
1. 입력을 한다.
<input type="text" onkeyup="processChange()" />
processChange = debounce(() => saveInput());가 실행된다.
const processChange = debounce(() => saveInput());
즉 debounce 함수를 실행하는데 그 안에 인자로 콜백함수가 들어가며 이름은 func로 바뀐다.
매개변수 : () => saveInput()
function debounce(func, timeout = 300) {
2. func가 실행되면서 비동기로 주르륵 실행된다.
2-1. let timer; timer라는 변수를 선언한다.
let timer;
2-2. 동시에 return이 돌면서 clearTimeout(timer); timer를 초기화한다.
return (...args) => {
clearTimeout(timer);
2-3. setTimeout이 timeout만큼 기다리고 그 안에 함수를 실행. (이때 timout은 초기값인 300ms)
timer = setTimeout(() => {
func.apply(this, args);
}, timeout);
};
timer = setTimeout(() => { func.apply(this, args); }, timeout);
이는 timer = setTimeout(() => { func.apply(this, args); }, 300); 이다.
setTimeout을 호출하면 '타이머 식별자(timer identifier)'가 반환되어 timer에 저장.
2-4. 만약 300ms 가 지나도록 더이상 입력이 없다면?
func.apply(this, args);
{ func.apply(this, args); }가 실행되어
미리 설정한 함수인 function saveInput() { console.log('Saving data'); 가 실행된다.
function saveInput() {
console.log('Saving data');
}
따라서 콘솔에 Saving data가 출력된다.
3. 그러나 사용자가 300ms가 되기 전에 다다다 값을 입력하고 있다면?
3-1. processChange = debounce(() => saveInput()) 이 함수가 실행이 되어 다시 func부터 실행이 된다.
<input type="text" onkeyup="processChange()" />
const processChange = debounce(() => saveInput());
function debounce(func, timeout = 300) {
3-2. let timer; timer 변수 설정
let timer;
return (...args) => { clearTimeout(timer); timer 초기화가 되어
clearTimeout(timer);
그 아래의 setTimeout은 실행되지 않게 된다.
따라서 300ms 만큼의 시간이 될 때까지 입력값이 없다면, 그 값을 가지고 검색할 수 있는 것이다.
반대의 경우 - 뒤이은 이벤트를 무시하는 방법
방금까지의 방법은 자동 저장이나 제안 옵션을 보여줄 때 좋다. 하지만 버튼 하나를 여러 번 클릭하는 사례에서는 어떨까?
: 마지막 클릭까지 기다리는 대신 첫 번째 클릭에서 이를 등록하고, 나머지를 무시
function debounce_leading(func, timeout = 300) {
let timer;
return (...args) => {
if (!timer) {
func.apply(this, args);
}
clearTimeout(timer);
timer = setTimeout(() => {
timer = undefined;
}, timeout);
};
}
- debounce_leading라는 함수를 정의
- setTimeout 함수는 자바스크립트에서 제공하는 비동기 함수이며,
첫 번째 인자로 주어진 함수를 두 번째 인자로 주어진 시간(밀리초 단위)이 지난 후에 실행한다.
여기서는 timeout이라는 시간이 경과하면 timer 변수를 undefined로 만드는 함수를 setTimeout에 전달한다.
1. debounce_leading 함수가 호출되면 timer 변수가 선언
let timer;
2. 함수가 호출될 때마다, timer가 존재하지 않는지 확인
- 이때 첫 번째 호출에서는 timer가 아직 정의되지 않았으므로 (값은 undefined)이므로 (!timer) 조건이 참
if (!timer) {
func.apply(this, args);
}
3. 이 경우, func 함수를 즉시 실행하고, timer에 setTimeout을 설정
- 이 setTimeout 함수는 timeout 시간이 지나면 timer를 undefined로 만든다.
3-1. func함수 실행결과는 콘솔에 값을 찍히게 한다.
function saveInput() {
console.log('Saving data');
}
3-2. timer 설정
timer = setTimeout(() => {
timer = undefined;
}, timeout);
4. 함수가 다시 호출되면, timer가 존재(timerID 반환후 저장)하므로 func 함수는 실행되지 않는다.
이때 분기별 timer 값은 다음과 같다.
1. 초기 상태
- debounce_leading 함수가 처음 호출되면, timer는 아직 정의되지 않은 상태
2. 첫 번째 함수 호출
- debounce_leading 함수가 처음 호출되면, (!timer) 조건식이 참이 되어 func 함수가 실행
그리고 timer에는 timeout 시간 후에 실행될 setTimeout 함수가 할당
- 이 시점에서 timer에는 setTimeout의 반환값인 타이머 ID가 저장
🌟따라서 이때 timer에 undefined나 null이 아닌 값이 저장되었기 때문에 (!timer) 조건식은 false가 되므로
다음 func 함수가 실행되지 않는 것이다.
3. 두 번째 이후 함수 호출
- debounce_leading 함수가 두 번째 이후로 호출되면, timer 값이 존재하므로 (!timer) 조건식이 거짓이 되고
func 함수는 실행되지 않음
- 그 대신 이전에 설정된 setTimeout은 clearTimeout에 의해 취소되고,
timer에는 다시 새로운 setTimeout 함수가 할당, 이 때도 timer에는 새로운 타이머 ID가 저장
4. 이벤트 없는 timeout 시간 경과
만약 timeout 시간 동안 debounce_leading 함수가 다시 호출되지 않으면, setTimeout 함수 내부의 코드가 실행
이 코드에 의해 timer 값은 undefined로 설정되며, 다음 이벤트가 발생할 때 func 함수가 다시 실행
5. 대신, 이전에 설정한 setTimeout이 취소되고, 새로운 setTimeout이 다시 설정.
이것이 debounce의 핵심 동작
즉, 연속된 이벤트가 발생하면 이전 이벤트의 처리는 취소되고 새 이벤트의 처리만을 진행
6. 이벤트가 timeout 시간(300ms) 동안 발생하지 않으면,
setTimeout에 의해 timer가 undefined로 만들어지고, 다음 이벤트가 발생할 때 func 함수가 다시 실행
debounce 기법의 장점
debounce 기법을 사용하면, 이벤트가 너무 빈번하게 발생하여(저장 등) 시스템에 부담을 주는 것을 막을 수 있다.
'[Dev] 🎯Self Study' 카테고리의 다른 글
[리액트에서 Next로] Next.js 기초 : SSR, CSR 렌더링 차이와 특징 (1) | 2024.01.08 |
---|---|
[리액트에서 Next로] Next.js 기초 : 초기 프로젝트 설정부터 네비게이션 (0) | 2024.01.06 |
[프로젝트 파일구조] demo 만들기 (0) | 2023.08.05 |
[Typescript] TS, 다시 처음부터 읽기 (2) (0) | 2023.07.25 |
[Typescript] TS, 다시 처음부터 읽기 (1) (0) | 2023.07.25 |