728x90
모던 자바스크립트 Deep Dive을 요약한 내용입니다.
41.1 호출 스케줄링
- 함수를 명시적으로 호출하지 않고 일정 시간이 경과한 이후에 호출되도록 함수 호출을 예약하려면 타이머 함수를 사용한다.
- 이를 호출 스케줄링이라 한다.
- 타이머를 생성하는 함수 setTimeout과 setInterval
- 타이머를 제거할 수 있는 함수 clearTimeout과 clearInterval
- 타이머 함수는 생성한 타이머가 만료되면 콜백 함수가 호출 된다.
- setTimeout 함수가 생성한 타이머는 단 한번 동작
- setInterval 함수가 생성한 타이머는 반복 동작
- setTimeout, setInterval은 비동기 처리 방식으로 동작
41.2 타이머 함수
41.2.1 setTimeout / clearTimeout
- setTimeout 함수는 두번째 인수로 전달받은 시간(ms, 1/1000초)로 단한번 동작하는 타이머
- 타이머가 만료되면 첫번째 인수로 전달받은 콜백 함수가 호출된다.매개변수 설명
func 타이머가 만료된 뒤 호출될 콜백 함수 delay 타이머 만료 시간, 인수 전달을 생략한 경우 기본값이 0이 지정된다. param1, param2, … 호출 스케줄링된 콜백 함수에 전달해야 할 인수가 존재하는 경우 세번째 이후의 인수로 전달할 수 있다. setTimeout(() => console.log('Hi!'), 1000) // Hi! setTimeout(name => console.log(`Hi! ${name}.`), 1000, 'Lee') // Hi! Lee. setTimeout(() => console.log('Hello!')) // Hello!
- const timeoutId = setTimeout(func|code[, delay, param1, param2, ...])
- setTimeout 함수는 생성된 타이머를 식별할 수 있는 고유한 타이머 id를 반환한다.
- 브라우저 환경의 경우 숫자
- Node.js 환경인 경우 객체
- clearTimeout 함수의 인수로 전달하여 타이머를 취소할 수 있다.
const timeoutId = setTimeout(func|code[, delay, param1, param2, ...])
41.2.2 setInterval / clearInterval
- setInterval 함수는 두번째 인수로 전달받은 시간(ms, 1/1000초)으로 반복동작하는 타이머를 생성
- 타이머가 만료될 때마다 첫번째 인수로 전달받은 콜백 함수가 반복 호출 된다.
- 두번째 인수로 전달받은 시간이 결과할 때마다 반복 실행
- setInterval 함수는 생성된 타이머를 식별할 수 있는 고유한 타이머 id를 반환한다.
- 브라우저 환경의 경우 숫자
- Node.js 환경인 경우 객체
- clearInterval 함수의 인수로 전달하여 타이머를 취소할 수 있다.
- let count = 1 const timeoutId = setInterval(() => { console.log(count) if (count++ === 5) { clearInterval(timeoutId) } }, 1000)
41.3 디바운스와 스로틀
- scroll, resize, input, mousemove, mouseover 같은 이벤트는 짧은 시간 간격으로 연속해서 발생한다.
- 이벤트 핸들러는 과도하게 호출되어 성능에 문제를 일으킬수 있다.
- 디바운스와 스로틀은 짧은 시간 간격으로 연속해서 발생하는 이벤트를 그룹화해서 과도한 이벤트 핸들러의 호출을 방지하는 프로그래밍 기법이다.
<!DOCTYPE html>
<html>
<body>
<button>Click me</button>
<pre>일반 클릭 이벤트 카운터 <span class="normal-msg">0</span></pre>
<pre>디바운스 클릭 이벤트 카운터 <span class="debounce-msg">0</span></pre>
<pre>스로틀 클릭 이벤트 카운터 <span class="throttle-msg">0</span></pre>
<script>
const $button = document.querySelector('button')
const $normalMsg = document.querySelector('.normal-msg')
const $debounceMsg = document.querySelector('.debounce-msg')
const $throttleMsg = document.querySelector('.throttle-msg')
const debounce = (callback, delay) => {
let timerId
return (event) => {
if (timerId) {
clearTimeout(timerId)
}
timerId = setTimeout(callback, delay, event)
}
}
const throttle = (callback, delay) => {
let timerId
return (event) => {
if (timerId) {
return
}
timerId = setTimeout(
() => {
callback(event)
timerId = null
},
delay,
event
)
}
}
$button.addEventListener('click', () => {
$normalMsg.textContent = +$normalMsg.textContent + 1
})
$button.addEventListener(
'click',
debounce(() => {
$debounceMsg.textContent = +$debounceMsg.textContent + 1
}, 500)
)
$button.addEventListener(
'click',
throttle(() => {
$throttleMsg.textContent = +$throttleMsg.textContent + 1
}, 500)
)
</script>
</body>
</html>
41.3.1 디바운스
- 디바운스는 짧은 시간 간격으로 이벤트가 연속해서 발생하면 이벤트 핸들러를 호출하지 않다가 일정시간이 경과한 이후에 이벤트 핸들러가 한번만 호출되도록 한다.
- 마지막에 한번만 이벤트 핸들러가 호출되도록 한다.
- input 이벤트가 짧은 시간 간격으로 연속해서 발생하는 경우
<!DOCTYPE html>
<html>
<body>
<input type="text" />
<div class="msg"></div>
<script>
const $input = document.querySelector('input')
const $msg = document.querySelector('.msg')
const debounce = (callback, delay) => {
let timerId
return (event) => {
if (timerId) {
clearTimeout(timerId)
}
timerId = setTimeout(callback, delay, event)
}
}
$input.oninput = debounce((e) => {
$msg.textContent = e.target.value
}, 300)
</script>
</body>
</html>
- 스로틀은 짧은 시간 간격으로 이벤트가 연속해서 발생하더라도 일정 시간 간격으로 이벤트 핸들러가 최대 한번만 호출되도록 한다.
- scroll 이벤트가 짧은 시간 간격으로 연속해서 발생하는 경우
<!DOCTYPE html>
<html>
<head>
<style>
.container {
width: 300px;
height: 300px;
background-color: rebeccapurple;
overflow: scroll;
}
.content {
width: 300px;
height: 1000vh;
}
</style>
</head>
<body>
<div class="container">
<div class="content"></div>
</div>
<div>
일반 이벤트 핸들러가 scroll 이벤트를 처리한 횟수:
<span class="normal-count">0</span>
</div>
<div>
스로틀 이벤트 핸들러가 scroll 이벤트를 처리한 횟수:
<span class="throttle-count">0</span>
</div>
<script>
const $container = document.querySelector('.container')
const $normalCount = document.querySelector('.normal-count')
const $throttleCount = document.querySelector('.throttle-count')
const throttle = (callback, delay) => {
let timerId
return (event) => {
if (timerId) {
return
}
timerId = setTimeout(
() => {
callback(event)
timerId = null
},
delay,
event
)
}
}
let normalCount = 0
$container.addEventListener('scroll', () => {
$normalCount.textContent = ++normalCount
})
let throttleCount = 0
$container.addEventListener(
'scroll',
throttle(() => {
$throttleCount.textContent = ++throttleCount
}, 100)
)
</script>
</body>
</html>
- 41.3.2 스로틀
- throttle 함수는 Underscore의 throttle 함수나 Lodash의 throttle 함수는 사용하는 것을 권장
728x90
'자바스크립트 > 모던 자바스크립트 Deep Dive' 카테고리의 다른 글
Ajax (0) | 2023.11.20 |
---|---|
비동기 프로그래밍 (0) | 2023.11.20 |
이벤트 (2) | 2023.11.20 |
브라우저의 렌더링 과정 (1) | 2023.11.17 |
Set과 Map (0) | 2023.11.17 |