호출 스케줄링 - 함수의 실행을 예약하는 방법
- 타이머 함수를 이용하면 일정 시간이 지난 후 특정 함수를 실행 가능하다.
타이머 함수
- javascript에서는 대표적인 타이머 함수는
setTimeout
과setInterval
가 있다.
setTimeout - 일정 시간이 지난 후 콜백 함수를 한번 호출
- setTimeout은 단 한번 동작하는 타이머 생성
- 타이머가 만료되면 전달받은 콜백 함수를 호출
- MDN - setTimeout
- setTimeout의 반환 값은 생성한 타이머에 대한 고유 id 값
- 타이머 고유 id 값은 실행 환경에 따라 다르다.
- 반환 값에 대한 예시 코드 및 결과
const firstTimerId = setTimeout(() => {
console.log('first callback 함수 호출');
}, 1000);
console.log('firstTimerId: ', firstTimerId);
const secondTimerId = setTimeout(() => {
console.log('second callback 함수 호출');
}, 1000);
console.log('secondTimerId: ', secondTimerId);
const thirdTimerId = setTimeout(() => {
console.log('third callback 함수 호출');
}, 1000);
console.log('thirdTimerId: ', thirdTimerId);
- 브라우저
- 타이머 id는 정수 값이며 1부터 시작하는 걸로 추측됨
- 타이머 id는 정수 값이며 1부터 시작하는 걸로 추측됨
- Node
- 타이머 id는 객체
- 타이머 id는 객체
setInterval - 일정 시간마다 콜백 함수를 호출
- setInterval은 일정 시간마다 만료되는(반복 동작하는) 타이머 생성
- 이 역시 타이머가 만료되면 전달받은 콜백 함수를 호출
- MDN - setInterval
- setInterval의 반환 값 역시 생성한 타이머에 대한 고유 id 값이다.
- setTimeout과 마찬가지로 타이머 고유 id 값은 실행 환경에 따라 다르다.
- setInterval 종료하는 코드 예시
let turn = 1;
const timerId = setInterval(() => {
console.log('현재 turn: ', turn);
if (turn === 10) {
clearInterval(timerId);
}
turn = turn + 1;
}, 1000);
// 출력 예시
// 현재 turn: 1
// 현재 turn: 2
// 현재 turn: 3
// ...
// ...
// 현재 turn: 9
// 현재 turn: 10
Debounce(디바운스)와 Throttle(스로틀) - setTimeout을 이용해서 이벤트의 빈번한 호출을 방지
🤔 왜 필요한가?
- 이벤트 핸들러에 등록된 작업이 무거운 작업일 때, 이벤트의 과도환 호출은 성능 저하를 초래할 수 있다.
- 이런 경우 디바운스와 스로틀을 사용하면 성능 저하를 예방할 수 있다.
예제 코드 및 구현 결과
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Timer 연습</title>
</head>
<body>
<h1>Timer 연습</h1>
<button id="button">버튼</button>
<div>
일반 클릭 이벤트 카운터
<span id="normal_counter"> 0 </span>
</div>
<div>
디바운스 클릭 이벤트 카운터
<span id="debounce_counter"> 0 </span>
</div>
<div>
스로틀 클릭 이벤트 카운터
<span id="throttle_counter"> 0 </span>
</div>
<script>
const $button = document.querySelector('#button');
const $normal_counter = document.querySelector('#normal_counter');
const $debounce_counter = document.querySelector('#debounce_counter');
const $throttle_counter = document.querySelector('#throttle_counter');
const debounce = (callback, delay) => {
let timerId;
return (event) => {
// delay가 지나기 전에 이벤트가 다시 발생하면 이전 timer는 취소됨
// 따라서 delay까지 이벤트가 발생하지 않아야 callback 함수가 실행된다.
if (timerId) clearTimeout(timerId);
timerId = setTimeout(callback, delay, event);
};
};
const throttle = (callback, delay) => {
let timerId;
return (event) => {
// delay가 지나기 전에 이벤트가 다시 발생해도 새로운 타이머가 생성되지 않음
// 따라서 delay 시간이 되면 callback이 호출되고 새로운 타이머가 생성된다.
if (timerId) return;
timerId = setTimeout(
() => {
callback(event);
timerId = null;
},
delay,
event
);
};
};
$button.addEventListener('click', () => {
$normal_counter.textContent = Number($normal_counter.textContent) + 1;
});
$button.addEventListener(
'click',
debounce(() => {
$debounce_counter.textContent = Number($debounce_counter.textContent) + 1;
}, 500)
);
$button.addEventListener(
'click',
throttle(() => {
$throttle_counter.textContent = Number($throttle_counter.textContent) + 1;
}, 500)
);
</script>
</body>
</html>
참고 자료
MDN Docs
모던 Javascript Deep Dive - 이웅모 저
'Programming > JS' 카테고리의 다른 글
[Javascript] Eslint 설정 파일 옵션 env, parserOptions (0) | 2022.04.21 |
---|---|
[Javascript] 예외 처리 (0) | 2022.02.21 |
[Javascript] 정보 은닉 (0) | 2022.02.20 |
[Javascript] 탭 이동 효과 구현하기 (0) | 2021.12.21 |
[Javascript] Eslint와 prettier 설치 및 vscode 에러 해결법 (2) | 2021.12.10 |