ํจ์๋ฅผ ๋ช ์์ ์ผ๋ก ํธ์ถํ๋ฉด ํจ์๊ฐ ์ฆ์ ์คํ๋๋ค. ๋ง์ฝ ํจ์๋ฅผ ๋ช ์์ ์ผ๋ก ํธ์ถํ์ง ์๊ณ ์ผ์ ์๊ฐ์ด ๊ฒฝ๊ณผ๋ ์ดํ์ ํธ์ถ๋๋๋ก ํจ์ ํธ์ถ์ ์์ฝํ๋ ค๋ฉด ํ์ด๋จธ ํจ์๋ฅผ ์ฌ์ฉํ๋ค. ์ด๋ฅผ ํธ์ถ ์ค์ผ์ค๋ง์ด๋ผ ํ๋ค.
์๋ฐ์คํฌ๋ฆฝํธ๋ ํ์ด๋จธ๋ฅผ ์์ฑํ ์ ์๋ ํ์ด๋จธ ํจ์ setTimeout๊ณผ setInterval, ํ์ด๋จธ๋ฅผ ์ ๊ฑฐํ ์ ์๋ ํ์ด๋จธ ํจ์ clearTimeout๊ณผ clearInterval์ ์ ๊ณตํ๋ค.
ํ์ด๋จธ ํจ์๋ ํธ์คํธ ๊ฐ์ฒด์ด๋ค. ํ์ด๋จธ ํจ์ setTimeout๊ณผ setInterval์ด ์์ฑํ ํ์ด๋จธ๊ฐ ๋ง๋ฃ๋๋ฉด ์ฝ๋ฐฑ ํจ์๊ฐ ํธ์ถ๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ ๋จ ํ๋์ ์คํ ์ปจํ
์คํธ ์คํ์ ๊ฐ๊ธฐ ๋๋ฌธ์ ๋ ๊ฐ์ง ์ด์์ ํ์คํฌ๋ฅผ ๋์์ ์คํํ ์ ์๋ค. ์ฆ, ์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ ์ฑ๊ธ ์ค๋ ๋๋ก ๋์ํ๋ค. ์ด๋ฌํ ์ด์ ๋ก setTimeout๊ณผ setInterval ํ์ด๋จธ ํจ์ set์ ๋น๋๊ธฐ(asynvhronous) ์ฒ๋ฆฌ ๋ฐฉ์์ผ๋ก ๋์ํ๋ค.
**setTimeout**
/ **clearTimeout**
setTimeout ํจ์๋ ๋ ๋ฒ์งธ ์ธ์๋ก ์ ๋ฌ๋ฐ์ ์๊ฐ์ผ๋ก ๋จ ํ ๋ฒ ๋์ํ๋ ํ์ด๋จธ๋ฅผ ์์ฑํ๋ค. ์ดํ ํ์ด๋จธ๊ฐ ๋ง๋ฃ๋๋ฉด ์ฒซ ๋ฒ์งธ ์ธ์๋ก ์ ๋ฌ๋ฐ์ ์ฝ๋ฐฑํจ์๊ฐ ํธ์ถ๋๋ค. ์ฆ, setTimeout ํจ์์ ์ฝ๋ฐฑ ํจ์๋ ๋ ๋ฒ์งธ ์ธ์๋ก ์ ๋ฌ๋ฐ์ ์๊ฐ ์ดํ๋ก ๋จ ํ ๋ฒ ์คํ๋๋๋ก ํธ์ถ ์ค์ผ์ผ๋ง ํ๋ค.
// 1์ด(1000ms) ํ ํ์ด๋จธ๊ฐ ๋ง๋ฃ๋๋ฉด ์ฝ๋ฐฑ ํจ์๊ฐ ํธ์ถ๋๋ค.
setTimeout(() => console.log('Hi!'), 1000);
// 1์ด(1000ms) ํ ํ์ด๋จธ๊ฐ ๋ง๋ฃ๋๋ฉด ์ฝ๋ฐฑ ํจ์๊ฐ ํธ์ถ๋๋ค.
// ์ด๋ ์ฝ๋ฐฑ ํจ์์ 'Lee'๊ฐ ์ธ์๋ก ์ ๋ฌ๋๋ค.
setTimeout(name => console.log(`Hi! ${name}.`), 1000, 'Lee');
// ๋ ๋ฒ์งธ ์ธ์(delay)๋ฅผ ์๋ตํ๋ฉด ๊ธฐ๋ณธ๊ฐ 0์ด ์ง์ ๋๋ค.
setTimeout(() => console.log('Hello!'));
// 1์ด(1000ms) ํ ํ์ด๋จธ๊ฐ ๋ง๋ฃ๋๋ฉด ์ฝ๋ฐฑ ํจ์๊ฐ ํธ์ถ๋๋ค.
// setTimeout ํจ์๋ ์์ฑ๋ ํ์ด๋จธ๋ฅผ ์๋ณํ ์ ์๋ ๊ณ ์ ํ ํ์ด๋จธ id๋ฅผ ๋ฐํํ๋ค.
const timerId = setTimeout(() => console.log('Hi!'), 1000);
// setTimeout ํจ์๊ฐ ๋ฐํํ ํ์ด๋จธ id๋ฅผ clearTimeout ํจ์์ ์ธ์๋ก ์ ๋ฌํ์ฌ ํ์ด๋จธ๋ฅผ
// ์ทจ์ํ๋ค. ํ์ด๋จธ๊ฐ ์ทจ์๋๋ฉด setTimeout ํจ์์ ์ฝ๋ฐฑ ํจ์๊ฐ ์คํ๋์ง ์๋๋ค.
clearTimeout(timerId);
**setInterval**
/ **clearInterval**
setInterval ํจ์๋ ๋ ๋ฒ์งธ ์ธ์๋ก ์ ๋ฌ๋ฐ์ ์๊ฐ์ ๋ฐ๋ณต ๋์ํ๋ ํ์ด๋จธ๋ฅผ ์์ฑํ๋ค. ์ดํ ํ์ด๋จธ๊ฐ ๋ง๋ฃ๋ ๋๋ง๋ค ์ฒซ ๋ฒ์งธ ์ธ์๋ก ์ ๋ฌ๋ฐ์ ์ฝ๋ฐฑ ํจ์๊ฐ ๋ฐ๋ณต ํธ์ถ๋๋ค. ์ด๋ ํ์ด๋จธ๊ฐ ์ทจ์๋ ๋๊น์ง ๊ณ์๋๋ค.
let count = 1;
// 1์ด(1000ms) ํ ํ์ด๋จธ๊ฐ ๋ง๋ฃ๋ ๋๋ง๋ค ์ฝ๋ฐฑ ํจ์๊ฐ ํธ์ถ๋๋ค.
// setInterval ํจ์๋ ์์ฑ๋ ํ์ด๋จธ๋ฅผ ์๋ณํ ์ ์๋ ๊ณ ์ ํ ํ์ด๋จธ id๋ฅผ ๋ฐํํ๋ค.
const timeoutId = setInterval(() => {
console.log(count); // 1 2 3 4 5
// count๊ฐ 5์ด๋ฉด setInterval ํจ์๊ฐ ๋ฐํํ ํ์ด๋จธ id๋ฅผ clearInterval ํจ์์
// ์ธ์๋ก ์ ๋ฌํ์ฌ ํ์ด๋จธ๋ฅผ ์ทจ์ํ๋ค. ํ์ด๋จธ๊ฐ ์ทจ์๋๋ฉด setInterval ํจ์์ ์ฝ๋ฐฑ ํจ์๊ฐ
// ์คํ๋์ง ์๋๋ค.
if (count++ === 5) clearInterval(timeoutId);
}, 1000);
scroll, resize, input, mousemove ๊ฐ์ ์ด๋ฒคํธ๋ค์ ์งง์ ์๊ฐ๋์ ์ฐ์์ ์ผ๋ก ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ ๋ฐ์ธ๋ฉ๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ๊ณผ๋ํ๊ฒ ํธ์ถ๋์ด ์ฑ๋ฅ์ด ์ ํ๋ ์ ์๋ค. ๋๋ฐ์ด์ค์ ์ค๋กํ์ ์งง์ ์๊ฐ ๊ฐ๊ฒฉ์ผ๋ก ์ฐ์ํด์ ๋ฐ์ํ๋ ์ด๋ฒคํธ๋ฅผ ๊ทธ๋ฃนํํด์ ๊ณผ๋ํ ์ด๋ฒคํธ ํธ๋ค๋ฌ์ ํธ์ถ์ ๋ฐฉ์งํ๋ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ฒ์ด๋ค.
<!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>
๋๋ฐ์ด์ค๋ ์งง์ ์๊ฐ ๊ฐ๊ฒฉ์ผ๋ก ์ด๋ฒคํธ๊ฐ ์ฐ์ํด์ ๋ฐ์ํ๋ฉด ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ํธ์ถํ์ง ์๋ค๊ฐ ์ผ์ ์๊ฐ์ด ๊ฒฝ๊ณผํ ์ดํ์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ํ ๋ฒ๋ง ํธ์ถ๋๋๋ก ํ๋ค. ์ฆ, ๋๋ฐ์ด์ค๋ ์งง์ ์๊ฐ ๊ฐ๊ฒฉ์ผ๋ก ๋ฐ์ํ๋ ์ด๋ฒคํธ๋ฅผ ๊ทธ๋ฃนํํด์ ๋ง์ง๋ง์ ํ ๋ฒ๋ง ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ํธ์ถ๋๋๋ก ํ๋ค.
<!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;
// debounce ํจ์๋ timerId๋ฅผ ๊ธฐ์ตํ๋ ํด๋ก์ ๋ฅผ ๋ฐํํ๋ค.
return event => {
// delay๊ฐ ๊ฒฝ๊ณผํ๊ธฐ ์ด์ ์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด ์ด์ ํ์ด๋จธ๋ฅผ ์ทจ์ํ๊ณ
// ์๋ก์ด ํ์ด๋จธ๋ฅผ ์ฌ์ค์ ํ๋ค.
// ๋ฐ๋ผ์ delay๋ณด๋ค ์งง์ ๊ฐ๊ฒฉ์ผ๋ก ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด callback์ ํธ์ถ๋์ง ์๋๋ค.
if (timerId) clearTimeout(timerId);
timerId = setTimeout(callback, delay, event);
};
};
// debounce ํจ์๊ฐ ๋ฐํํ๋ ํด๋ก์ ๊ฐ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ก ๋ฑ๋ก๋๋ค.
// 300ms๋ณด๋ค ์งง์ ๊ฐ๊ฒฉ์ผ๋ก input ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด debounce ํจ์์ ์ฝ๋ฐฑ ํจ์๋
// ํธ์ถ๋์ง ์๋ค๊ฐ 300ms ๋์ input ์ด๋ฒคํธ๊ฐ ๋ ์ด์ ๋ฐ์ํ๋ฉด ํ ๋ฒ๋ง ํธ์ถ๋๋ค.
$input.oninput = debounce(e => {
$msg.textContent = e.target.value;
}, 300);
</script>
</body>
</html>
์ฌ์ฉ์๊ฐ ์ ๋ ฅ์ ์๋ฃํ๋์ง ์ฌ๋ถ๋ ์ ํํ ์ ์ ์์ผ๋ฏ๋ก ์ผ์ ์๊ฐ ๋์ ํ ์คํธ ์ ๋ ฅ ํ๋์ ๊ฐ์ ์ ๋ ฅํ์ง ์์ผ๋ฉด ์ ๋ ฅ์ด ์๋ฃ๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผํ๋ค. ์ด๋ฅผ ์ํด debounce ํจ์๊ฐ ๋ฐํํ ํจ์๋ debounce ํจ์์ ๋ ๋ฒ์งธ ์ธ์๋ก ์ ๋ฌํ ์๊ฐ(delay)๋ณด๋ค ์งง์ ๊ฐ๊ฒฉ์ผ๋ก ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด ์ด์ ํ์ด๋จธ๋ฅผ ์ทจ์ํ๊ณ ์๋ก์ด ํ์ด๋จธ๋ฅผ ์ฌ์ค์ ํ๋ค. ๋ฐ๋ผ์ delay ๋ณด๋ค ์งง์ ๊ฐ๊ฒฉ์ผ๋ก ์ด๋ฒคํธ๊ฐ ์ฐ์ํด์ ๋ฐ์ํ๋ฉด debounce ํจ์์ ์ฒซ ๋ฒ์งธ ์ธ์๋ก ์ ๋ฌํ ์ฝ๋ฐฑ ํจ์๋ ํธ์ถ๋์ง ์๋ค๊ฐ delay ๋์ input ์ด๋ฒคํธ๊ฐ ๋ ์ด์ ๋ฐ์ํ์ง ์์ผ๋ฉด ํ๋ฒ๋ง ํธ์ถ๋๋ค.
์ค๋กํ์ ์งง์ ์๊ฐ ๊ฐ๊ฒฉ์ผ๋ก ์ด๋ฒคํธ๊ฐ ์ฐ์ํด์ ๋ฐ์ํ๋๋ผ๋ ์ผ์ ์๊ฐ ๊ฐ๊ฒฉ์ผ๋ก ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ์ต๋ ํ ๋ฒ๋ง ํธ์ถ๋๋๋ก ํ๋ค. ์ฆ, ์ค๋กํ์ ์งง์ ์๊ฐ ๊ฐ๊ฒฉ์ผ๋ก ์ฐ์ํด์ ๋ฐ์ํ๋ ์ด๋ฒคํธ๋ฅผ ๊ทธ๋ฃนํํด์ ์ผ์ ์๊ฐ ๋จ์๋ก ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ํธ์ถ๋๋๋ก ํธ์ถ ์ฃผ๊ธฐ๋ฅผ ๋ง๋ ๋ค.
<!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;
// throttle ํจ์๋ timerId๋ฅผ ๊ธฐ์ตํ๋ ํด๋ก์ ๋ฅผ ๋ฐํํ๋ค.
return event => {
// delay๊ฐ ๊ฒฝ๊ณผํ๊ธฐ ์ด์ ์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด ์๋ฌด๊ฒ๋ ํ์ง ์๋ค๊ฐ
// delay๊ฐ ๊ฒฝ๊ณผํ์ ๋ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด ์๋ก์ด ํ์ด๋จธ๋ฅผ ์ฌ์ค์ ํ๋ค.
// ๋ฐ๋ผ์ delay ๊ฐ๊ฒฉ์ผ๋ก callback์ด ํธ์ถ๋๋ค.
if (timerId) return;
timerId = setTimeout(() => {
callback(event);
timerId = null;
}, delay, event);
};
};
let normalCount = 0;
$container.addEventListener('scroll', () => {
$normalCount.textContent = ++normalCount;
});
let throttleCount = 0;
// throttle ํจ์๊ฐ ๋ฐํํ๋ ํด๋ก์ ๊ฐ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ก ๋ฑ๋ก๋๋ค.
$container.addEventListener('scroll', throttle(() => {
$throttleCount.textContent = ++throttleCount;
}, 100));
</script>
</body>
</html>