window.requestAnimationFrame() ์๋ฒฝ ์ ๋ฆฌ (MDN Web Docs)
์ด ๋ฌธ์๋ MDN Web Docs์ window.requestAnimationFrame() ํ์ด์ง๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํต์ฌ ๋ด์ฉ์ ์์ธํ๊ฒ ์ ๋ฆฌํ๊ณ , ์ดํด๋ฅผ ๋๊ธฐ ์ํด ์ถ๊ฐ ์ค๋ช ๊ณผ ์์ ์ฝ๋๋ฅผ ํฌํจํฉ๋๋ค.
1. requestAnimationFrame()์ด๋?
- ์ ์: window.requestAnimationFrame()์ ๋ธ๋ผ์ฐ์ ์๊ฒ ์ํํ๊ธฐ๋ฅผ ์ํ๋ ์ ๋๋ฉ์ด์ ์ ์๋ฆฌ๊ณ , ๋ค์ ๋ฆฌํ์ธํธ(repaint)๊ฐ ์งํ๋๊ธฐ ์ ์ ํด๋น ์ ๋๋ฉ์ด์ ์ ์ ๋ฐ์ดํธํ๋ ํจ์๋ฅผ ํธ์ถํ๋๋ก ์์ฒญํ๋ ๋ฉ์๋์ ๋๋ค. ์ฆ, ๋ธ๋ผ์ฐ์ ์ ๋ ๋๋ง ์ฃผ๊ธฐ์ ๋ง์ถฐ์ ์ ๋๋ฉ์ด์ ์ ๋ถ๋๋ฝ๊ฒ ์ฒ๋ฆฌํ ์ ์๊ฒ ํด์ฃผ๋ API์ ๋๋ค.
- ๋์ ๋ฐฉ์:
- requestAnimationFrame()์ ์ฝ๋ฐฑ ํจ์๋ฅผ ์ ๋ฌํฉ๋๋ค.
- ๋ธ๋ผ์ฐ์ ๋ ๋ค์ ๋ฆฌํ์ธํธ(ํ๋ฉด ๊ฐฑ์ ) ์ ์ ์ด ์ฝ๋ฐฑ ํจ์๋ฅผ ์คํํฉ๋๋ค.
- ์ฝ๋ฐฑ ํจ์ ๋ด์์ ์ ๋๋ฉ์ด์ ๊ด๋ จ DOM ์กฐ์(์คํ์ผ ๋ณ๊ฒฝ ๋ฑ)์ ์ํํฉ๋๋ค.
- ํ์ํ๋ค๋ฉด, ์ฝ๋ฐฑ ํจ์ ๋ด์์ ๋ค์ requestAnimationFrame()์ ํธ์ถํ์ฌ ์ ๋๋ฉ์ด์ ์ ๊ณ์ ์งํํฉ๋๋ค. (์ฌ๊ท์ ํธ์ถ)
- ์ฅ์ :
- ๋ถ๋๋ฌ์ด ์ ๋๋ฉ์ด์ : ๋ธ๋ผ์ฐ์ ์ ๋ฆฌํ์ธํธ ์ฃผ๊ธฐ์ ๋ง์ถฐ์ ์ ๋๋ฉ์ด์ ์ ์คํํ๋ฏ๋ก, setInterval์ด๋ setTimeout์ ์ฌ์ฉํ๋ ๊ฒ๋ณด๋ค ํจ์ฌ ๋ถ๋๋ฝ๊ณ ์์ฐ์ค๋ฌ์ด ์ ๋๋ฉ์ด์ ์ ๋ง๋ค ์ ์์ต๋๋ค.
- ์ฑ๋ฅ ์ต์ ํ:
- ๋นํ์ฑ ํญ ์ต์ ํ: ๋ธ๋ผ์ฐ์ ํญ์ด ๋นํ์ฑํ(๋ฐฑ๊ทธ๋ผ์ด๋์ ์๊ฑฐ๋, ์ต์ํ๋ ๊ฒฝ์ฐ)๋๋ฉด requestAnimationFrame()์ ์ฝ๋ฐฑ ํจ์ ์คํ์ ์ผ์ ์ค์งํ์ฌ CPU/GPU ์ฌ์ฉ๋์ ์ค์ ๋๋ค. ๋ฐฐํฐ๋ฆฌ ์๋ชจ๋ฅผ ์ค์ด๊ณ , ๋ค๋ฅธ ์์ ์ ๋ฆฌ์์ค๋ฅผ ํ ๋นํ ์ ์๊ฒ ํด์ค๋๋ค.
- ํ๋ ์ ์๋ ์กฐ์ : ๋ธ๋ผ์ฐ์ ๋ ํ์ฌ ์์คํ ๋ถํ ๋ฐ ๋์คํ๋ ์ด ์ฃผ์ฌ์จ์ ๋ง์ถฐ์ requestAnimationFrame() ์ฝ๋ฐฑ ํธ์ถ ๋น๋๋ฅผ ์๋์ผ๋ก ์กฐ์ ํฉ๋๋ค. ๋์ ์ฃผ์ฌ์จ(high refresh rate) ๋ชจ๋ํฐ์์๋ ๋ ์์ฃผ ํธ์ถํ์ฌ ๋ ๋ถ๋๋ฌ์ด ์ ๋๋ฉ์ด์ ์ ์ ๊ณตํ๊ณ , ๋ฎ์ ์ฃผ์ฌ์จ ๋ชจ๋ํฐ์์๋ ๋ถํ์ํ ์ฐ์ฐ์ ์ค์ ๋๋ค.
- ๋๊ธฐํ: requestAnimationFrame์ผ๋ก ํธ์ถ๋๋ ์ฝ๋ฐฑํจ์๋, ๋จ์ผ ํ๋ ์ ์์์ ๋ชจ๋ ์คํ๋จ.
- setInterval/setTimeout๊ณผ์ ๋น๊ต
๊ธฐ๋ฅ | requestAnimationFrame | setInterval / setTimeout |
์ ๋๋ฉ์ด์ ์ต์ ํ | ๋ธ๋ผ์ฐ์ ์ต์ ํ (๋ถ๋๋ฌ์) | ์ต์ ํ ์์ (๋๊น ๊ฐ๋ฅ์ฑ) |
๋นํ์ฑ ํญ ์ฒ๋ฆฌ | ์๋ ์ผ์ ์ค์ง (์ฑ๋ฅ ์ ์ฝ) | ๊ณ์ ์คํ (์์ ๋ญ๋น) |
ํธ์ถ ์ฃผ๊ธฐ | ๋ธ๋ผ์ฐ์ ๋ฆฌํ์ธํธ ์ฃผ๊ธฐ | ์ง์ ๋ ์๊ฐ ๊ฐ๊ฒฉ (๋ฐ๋ฆฌ์ด) |
์ ํ๋ | ๋์ (๋ธ๋ผ์ฐ์ ์ ์ต์ ํ) | ๋ฎ์ (์์คํ ๋ถํ์ ๋ฐ๋ผ ์ง์ฐ๋ ์ ์์) |
์ฃผ ์ฌ์ฉ ๋ชฉ์ | ์ ๋๋ฉ์ด์ , ๋ถ๋๋ฌ์ด UI ๋ณํ | ์ฃผ๊ธฐ์ ์ธ ์์ , ์ผ์ ์๊ฐ ํ ์คํ (์ ๋๋ฉ์ด์ ์๋ ๋ถ์ ํฉ) |
2. ๊ตฌ๋ฌธ (Syntax)
JavaScript
let requestId = window.requestAnimationFrame(callback);
- callback: ๋ค์ ๋ฆฌํ์ธํธ ๋ ํธ์ถ๋ ํจ์์ ๋๋ค. ์ด ํจ์๋ _๋จ์ผ ์ธ์_๋ก DOMHighResTimeStamp ๊ฐ์ ๋ฐ์ต๋๋ค. ์ด ๊ฐ์ requestAnimationFrame์ด ์ฝ๋ฐฑ์ ์คํํ๊ธฐ ์์ํ๋ ์์ ์ ์ ๋ฐํ ์๊ฐ(๋ฐ๋ฆฌ์ด ๋จ์)์ ๋ํ๋ ๋๋ค. performance.now()๋ก ์ป์ ๊ฐ๊ณผ ์ ์ฌํฉ๋๋ค.
- requestId: requestAnimationFrame() ํธ์ถ์ ์๋ณํ๋ ๊ณ ์ ํ ์ซ์ ID์ ๋๋ค. ์ด ID๋ฅผ cancelAnimationFrame(requestId)์ ์ ๋ฌํ์ฌ ์ ๋๋ฉ์ด์ ์ ์ทจ์ํ ์ ์์ต๋๋ค.
3. ์์ ์ฝ๋
3.1. ๊ฐ๋จํ ์ ๋๋ฉ์ด์
HTML
<!DOCTYPE html>
<html>
<head>
<title>requestAnimationFrame Example</title>
<style>
#box {
width: 100px;
height: 100px;
background-color: red;
position: absolute;
left: 0;
}
</style>
</head>
<body>
<div id="box"></div>
<script>
const box = document.getElementById('box');
let position = 0;
let requestId;
function animate() {
position += 2; // ์ด๋ ๊ฑฐ๋ฆฌ
box.style.left = position + 'px'; // CSS ์์ฑ ๋ณ๊ฒฝ (left)
if (position < 200) {
requestId = requestAnimationFrame(animate); // ๋ค์ ํ๋ ์ ์์ฒญ (์ฌ๊ท ํธ์ถ)
}
}
requestId = requestAnimationFrame(animate); // ์ ๋๋ฉ์ด์
์์
// ์ ๋๋ฉ์ด์
์ทจ์ (์์)
// setTimeout(() => {
// cancelAnimationFrame(requestId);
// }, 2000); // 2์ด ํ ์ ๋๋ฉ์ด์
์ค์ง
</script>
</body>
</html>
- animate() ํจ์๋ ๋ฐ์ค์ left ์์น๋ฅผ ๋ณ๊ฒฝํ์ฌ ์ค๋ฅธ์ชฝ์ผ๋ก ์ด๋์ํค๋ ์ญํ ์ ํฉ๋๋ค.
- requestAnimationFrame(animate)๋ฅผ ํธ์ถํ์ฌ ์ ๋๋ฉ์ด์ ์ ์์ํฉ๋๋ค.
- animate() ํจ์ ๋ด์์ ๋ค์ requestAnimationFrame(animate)๋ฅผ ํธ์ถํ์ฌ ์ ๋๋ฉ์ด์ ์ ๊ณ์ ์งํํฉ๋๋ค. (์ฌ๊ท ํธ์ถ)
- position์ด 200๋ณด๋ค ์์ ๋๋ง ๋ค์ ํ๋ ์์ ์์ฒญํ์ฌ, ๋ฐ์ค๊ฐ ํน์ ์์น๊น์ง๋ง ์ด๋ํ๋๋ก ํฉ๋๋ค.
- setTimeout๊ณผ cancelAnimationFrame์ ์ฌ์ฉํ์ฌ, ์ ๋๋ฉ์ด์ ์ ์ค๊ฐ์ ๋ฉ์ถ ์ ์์ต๋๋ค.
3.2. ์๊ฐ ๊ธฐ๋ฐ ์ ๋๋ฉ์ด์ (Time-based animation)
requestAnimationFrame ์ฝ๋ฐฑ์ ์ ๋ฌ๋๋ DOMHighResTimeStamp๋ฅผ ์ฌ์ฉํ์ฌ ์๊ฐ ๊ธฐ๋ฐ ์ ๋๋ฉ์ด์ ์ ๋ง๋ค ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ํ๋ ์ ์๋์ ๊ด๊ณ์์ด ์ผ์ ํ ์๋๋ก ์ ๋๋ฉ์ด์ ์ ์คํํ ์ ์์ต๋๋ค.
HTML
<!DOCTYPE html>
<html>
<head>
<title>Time-based Animation</title>
<style>
#box {
width: 100px;
height: 100px;
background-color: blue;
position: absolute;
left: 0;
}
</style>
</head>
<body>
<div id="box"></div>
<script>
const box = document.getElementById('box');
let start = null;
const duration = 2000; // ์ ๋๋ฉ์ด์
์ง์ ์๊ฐ (๋ฐ๋ฆฌ์ด)
function animate(timestamp) {
if (!start) start = timestamp; // ์ฒ์ ์์ ์๊ฐ์ ๊ธฐ๋ก
const progress = timestamp - start; // ๊ฒฝ๊ณผ ์๊ฐ ๊ณ์ฐ
// 0 ~ 1 ์ฌ์ด์ ์งํ๋ฅ ๊ณ์ฐ (duration์ผ๋ก ๋๋๊ธฐ)
const normalizedProgress = Math.min(progress / duration, 1);
// ์งํ๋ฅ ์ ๋ฐ๋ผ ์์น ๊ณ์ฐ (ease-out ํจ์ ์ ์ฉ)
const position = easeOutCubic(normalizedProgress) * 300; // ์ต๋ 300px ์ด๋
box.style.left = position + 'px';
if (progress < duration) {
requestAnimationFrame(animate); // ๋ค์ ํ๋ ์ ์์ฒญ
}
}
// Ease-out cubic ํจ์ (๋ถ๋๋ฌ์ด ๊ฐ์ ํจ๊ณผ)
function easeOutCubic(t) {
return 1 - Math.pow(1 - t, 3);
}
//๋ค๋ฅธ easing ํจ์ ์์
/* function easeInOutQuad(t: number): number {
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
}*/
requestAnimationFrame(animate); // ์ ๋๋ฉ์ด์
์์
</script>
</body>
</html>
- animate(timestamp): timestamp ์ธ์๋ requestAnimationFrame์ด ์ฝ๋ฐฑ ํจ์์ ์ ๋ฌํ๋ ํ์ฌ ์๊ฐ(DOMHighResTimeStamp)์ ๋๋ค.
- start: ์ ๋๋ฉ์ด์ ์์ ์๊ฐ์ ์ ์ฅํฉ๋๋ค. animate() ํจ์๊ฐ ์ฒ์ ํธ์ถ๋ ๋ performance.now()๋ฅผ ์ฌ์ฉํ์ฌ ์ด๊ธฐํ๋ฉ๋๋ค.
- progress: ์์ ์๊ฐ(start)์ผ๋ก๋ถํฐ ๊ฒฝ๊ณผ๋ ์๊ฐ์ ๊ณ์ฐํฉ๋๋ค.
- normalizedProgress: ๊ฒฝ๊ณผ ์๊ฐ์ ์ ๋๋ฉ์ด์ ์ง์ ์๊ฐ(duration)์ผ๋ก ๋๋์ด 0๊ณผ 1 ์ฌ์ด์ ์งํ๋ฅ ์ ๊ณ์ฐํฉ๋๋ค. Math.min์ ์ฌ์ฉํ์ฌ ์งํ๋ฅ ์ด 1์ ๋์ง ์๋๋ก ํฉ๋๋ค.
- easeOutCubic(normalizedProgress): easing ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๋ถ๋๋ฌ์ด ๊ฐ์/๊ฐ์ ํจ๊ณผ๋ฅผ ์ ์ฉํฉ๋๋ค.
- position: easing ํจ์์์ ๋ฐํ๋ ๊ฐ์ ๊ธฐ๋ฐ์ผ๋ก, ์ด๋ํ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ์ฐํฉ๋๋ค.
- box.style.left = position + 'px';: ๊ณ์ฐ๋ ์์น๋ก ๋ฐ์ค๋ฅผ ์ด๋์ํต๋๋ค.
- if (progress < duration): ์ ๋๋ฉ์ด์ ์ด ์๋ฃ๋์ง ์์์ผ๋ฉด requestAnimationFrame(animate)๋ฅผ ๋ค์ ํธ์ถํ์ฌ ๋ค์ ํ๋ ์์ ์์ฒญํฉ๋๋ค.
4. cancelAnimationFrame()
- ์ ์: cancelAnimationFrame()์ ์ด์ ์ requestAnimationFrame()์ผ๋ก ์์ฝ๋ ์ ๋๋ฉ์ด์ ํ๋ ์ ์์ฒญ์ ์ทจ์ํ๋ ๋ฉ์๋์ ๋๋ค.
- ๊ตฌ๋ฌธ:
window.cancelAnimationFrame(requestId);
- requestId: requestAnimationFrame()์ด ๋ฐํํ ID์ ๋๋ค.
- JavaScript
- ์์ :
let requestId = requestAnimationFrame(animate); // ์ ๋๋ฉ์ด์ ์ทจ์ cancelAnimationFrame(requestId);
- JavaScript
์์ฝ
requestAnimationFrame()์ ๋ธ๋ผ์ฐ์ ํ๊ฒฝ์์ ๋ถ๋๋ฝ๊ณ ํจ์จ์ ์ธ ์ ๋๋ฉ์ด์ ์ ๊ตฌํํ๋ ๋ฐ ํ์์ ์ธ API์ ๋๋ค. ๋ธ๋ผ์ฐ์ ์ ๋ฆฌํ์ธํธ ์ฃผ๊ธฐ์ ๋ง์ถฐ์ ์ ๋๋ฉ์ด์ ์ ์ ๋ฐ์ดํธํ๋ฏ๋ก, setInterval์ด๋ setTimeout์ ์ฌ์ฉํ๋ ๊ฒ๋ณด๋ค ์ฑ๋ฅ์ด ์ข๊ณ ์์ฐ์ค๋ฌ์ด ์ ๋๋ฉ์ด์ ์ ๋ง๋ค ์ ์์ต๋๋ค. cancelAnimationFrame()์ ์ฌ์ฉํ์ฌ ์ ๋๋ฉ์ด์ ์ ์ค์งํ ์ ์์ต๋๋ค. ์๊ฐ ๊ธฐ๋ฐ ์ ๋๋ฉ์ด์ ์ ๊ตฌํํ๋ฉด ํ๋ ์ ์๋์ ๊ด๊ณ์์ด ์ผ์ ํ ์๋๋ก ์ ๋๋ฉ์ด์ ์ ์คํํ ์ ์์ต๋๋ค.
https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame
Window: requestAnimationFrame() method - Web APIs | MDN
The window.requestAnimationFrame() method tells the browser you wish to perform an animation. It requests the browser to call a user-supplied callback function before the next repaint.
developer.mozilla.org