🚘

ch7 - 3. requestAnimationFrame

index

0. μ• λ‹ˆλ©”μ΄μ…˜ ꡬ동 ν”„λ‘œμ„ΈμŠ€

λ°©λ¬Έν•œ μ›ΉνŽ˜μ΄μ§€μ˜ μ• λ‹ˆλ©”μ΄μ…˜μ΄ μ‚΄μ•„ μ›€μ§μ΄λŠ” κ²ƒμ²˜λŸΌ μžμ—°μŠ€λŸ¬μš΄κ°€μš”? μ•„λ§ˆ κ·Έ μ΄μœ λŠ” ν•΄λ‹Ή μ• λ‹ˆλ©”μ΄μ…˜μ˜ 1μ΄ˆλ‹Ή ν”„λ ˆμž„ 개수(fps)κ°€ 많기 λ•Œλ¬ΈμΌ κ²ƒμž…λ‹ˆλ‹€. 졜근의 기기듀은 μžμ—°μŠ€λŸ¬μš΄ μ‹œκ° 효과λ₯Ό μœ„ν•΄ μ΄ˆλ‹Ή 60회의 화면을 κ·Έλ €λ‚΄κ³€ ν•˜λŠ”λ°μš”. 이 경우 각 ν”„λ ˆμž„μ—λŠ” 16ms κ°€λŸ‰μ˜ μ‹œκ°„λ§Œ ν• λ‹Ήλ©λ‹ˆλ‹€(1초/60 = 16.66ms).
그런데 λΈŒλΌμš°μ €κ°€ 이 λͺ¨λ“  ν”„λ ˆμž„μ„ κ΅¬λ™ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ‹€ν–‰ μ€€λΉ„ μ‹œκ°„μ΄ ν•„μš”ν•©λ‹ˆλ‹€. λ”°λΌμ„œ 10ms λ™μ•ˆ λͺ¨λ“  ꡬ동 μ€€λΉ„(λ Œλ”λ§)λ₯Ό λ§ˆμ³μ•Ό ν•©λ‹ˆλ‹€. λ§Œμ•½ 이λ₯Ό μ œν•œ μ‹œκ°„(10ms) 내에 해내지 λͺ»ν•˜λ©΄, μš°λ¦¬κ°€ μ’…μ’… μ›ΉνŽ˜μ΄μ§€μ—μ„œ λ°œκ²¬ν•˜κ³€ ν•˜λŠ” μ• λ‹ˆλ©”μ΄μ…˜ 버벅거림이 μΌμ–΄λ‚©λ‹ˆλ‹€.
Β 
λ Œλ”λ§ νŒŒμ΄ν”„λΌμΈ μš”μ†Œλ“€ (좜처 )λ Œλ”λ§ νŒŒμ΄ν”„λΌμΈ μš”μ†Œλ“€ (좜처 )
λ Œλ”λ§ νŒŒμ΄ν”„λΌμΈ μš”μ†Œλ“€ (좜처 )

1. setTimeoutκ³Ό setInterval의 ν•œκ³„

μ•ˆνƒ€κΉκ²Œλ„, setTimeoutκ³Ό setInterval 이 두 ν•¨μˆ˜λ₯Ό μ΄μš©ν•œλ‹€λ©΄ μ• λ‹ˆλ©”μ΄μ…˜μ΄ 생각보닀 λΆ€λ“œλŸ½κ²Œ κ΅¬λ™λ˜μ§€ μ•Šμ„ 수 μžˆμŠ΅λ‹ˆλ‹€. κ·Έ μ΄μœ λŠ” 이 두 ν•¨μˆ˜κ°€ 주어진 μ‹œκ°„ 내에 콜백만 ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. 즉 ν”„λ ˆμž„ μ‹œμž‘ μ‹œμ μ΄λ‚˜ μ• λ‹ˆλ©”μ΄μ…˜μ˜ λ Œλ”λ§ ν”„λ‘œμ„ΈμŠ€λ₯Ό κ³ λ €ν•˜μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€. 이 λ•Œλ¬Έμ— μ• λ‹ˆλ©”μ΄μ…˜μ΄ λ²„λ²…λŒ€λŠ” λ¬Έμ œκ°€ λ°œμƒν•©λ‹ˆλ‹€.
λ˜ν•œ, setTimeoutκ³Ό setInterval은 μ‚¬μš©μžκ°€ νŽ˜μ΄μ§€λ₯Ό 보지 μ•ŠλŠ” μ‹œμ μ—μ„œλ„ κ³„μ†ν•΄μ„œ 싀행돼, 배터리 수λͺ…μ΄λ‚˜ μ„±λŠ₯을 ν•˜λ½μ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€.
notion imagenotion image
setTimeout이 λΈŒλΌμš°μ €μ˜ μ• λ‹ˆλ©”μ΄μ…˜ ꡬ동 ν”„λ‘œμ„ΈμŠ€λ₯Ό μ΄ν•΄ν•˜μ§€ μ•Šκ³  κ΅¬ν˜„λ˜λŠ” μž₯λ©΄ μ˜ˆμ‹œ (좜처 )
Β 
λ”°λΌμ„œ 만일 λΆ€λ“œλŸ½κ³  λŠκΉ€ μ—†λŠ” ꡬ동을 μ›ν•œλ‹€λ©΄, 두 ν•¨μˆ˜λŠ” μ μ ˆν•œ κΈ°λŠ₯을 μˆ˜ν–‰ν•˜μ§€ μ•Šμ„ 수 μžˆμŠ΅λ‹ˆλ‹€. λ”λΆˆμ–΄ μ‹€ν–‰ μ‹œκ°„μ΄ κΈΈκ±°λ‚˜ 타이밍이 쒋지 μ•Šμ€ μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” μ„±λŠ₯ 문제λ₯Ό μ‰½κ²Œ μΌμœΌν‚€κ³€ ν•©λ‹ˆλ‹€. μ•ˆμ •μ μΈ μ›Ή μ• λ‹ˆλ©”μ΄μ…˜μ„ λ§Œλ“€κ³  μ‹Άλ‹€λ©΄, 이 문제λ₯Ό μ΅œμ†Œν™”ν•  방법을 μ°Ύμ•„μ•Ό ν•©λ‹ˆλ‹€.

2. requestAnimationFrame

이에 λŒ€μ•ˆμ΄ 될 ν•¨μˆ˜κ°€ λ°”λ‘œ requestAnimationFrameμž…λ‹ˆλ‹€. 이 ν•¨μˆ˜λŠ” λ Œλ”λ§ νŒŒμ΄ν”„λΌμΈ λ‚΄μ˜ λ¦¬νŽ˜μΈνŠΈκ°€ μ§„ν–‰λ˜κΈ° 전에 μ‹€ν–‰ν•  μ½œλ°±μ„ 인자둜 λ°›μ•„ λΈŒλΌμš°μ €λ‘œ ν•˜μ—¬κΈˆ μ›ν•˜λŠ” ν•¨μˆ˜κ°€ μ μ ˆν•œ 타이밍에 μ‹€ν–‰λ˜κ²Œλ” ν•©λ‹ˆλ‹€. 즉 ν”„λ ˆμž„ κ°œμˆ˜κ°€ λ§Žμ€ μ• λ‹ˆλ©”μ΄μ…˜μ΄ μžμ—°μŠ€λŸ½κ²Œ κ΅¬λ™λ˜κΈ° μœ„ν•΄, 각 ν”„λ ˆμž„ μ‹œμž‘ μ‹œμ κ³Ό ν•¨μˆ˜ ꡬ동 μ‹œμ μ„ λ§žμΆ”λ„λ‘ requestAnimationFrame이 λΈŒλΌμš°μ €μ—κ²Œ λͺ…령을 λ‚΄λ¦¬λŠ” 것이죠. (λ Œλ”λ§ νŒŒμ΄ν”„λΌμΈμ˜ μ‹œμž‘ μ‹œμ κ³Ό ν”„λ ˆμž„ μ‹œμž‘ μ‹œμ μ„ λ§žμΆ”λŠ” κΈ°λŠ₯을 ν•˜λŠ” κ²λ‹ˆλ‹€!)
그럼, λ™κ·Έλž€ 원이 μ™Όμͺ½μ—μ„œ 였λ₯Έμͺ½μœΌλ‘œ λΉ λ₯΄κ²Œ μ΄λ™ν•˜λŠ” κ°„λ‹¨ν•œ μ• λ‹ˆλ©”μ΄μ…˜μ„ κ΅¬ν˜„ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.
λ¨Όμ € λ™κ·Έλž€ 원을 λ§Œλ“€μ–΄μ£Όμ–΄μ•Ό ν•©λ‹ˆλ‹€.
<!DOCTYPE html> <html> <head> <title>moving circle</title> <style type="text/css"> .circle{ position: relative; border: 1px solid yellow; border-radius:50px; background: yellow; width:100px; height:100px; } </style> </head> <body> <div class="circle"></div>
μ΄λ ‡κ²Œ λ…Έλž€μƒ‰ 동그라미λ₯Ό λ§Œλ“€μ–΄ μ£Όμ…¨λ‹€λ©΄ μ΄μ œλŠ”, go()λΌλŠ” ν•¨μˆ˜λ₯Ό λ§Œλ“€μ–΄λ³΄κ² μŠ΅λ‹ˆλ‹€.
var touch = 0; var a = document.querySelector(".circle"); var fast = 0; function go() { a.style.left = ((count += 5) % 700) + "px"; // μ§€μ†μ μœΌλ‘œ styleνƒœκ·Έμ— 속도λ₯Ό λ‚Ό 수 있게 countλ₯Ό μΆ”κ°€ν•΄μ€€λ‹€. touch = requestAnimationFrame(go); } requestAnimationFrame(go);
λ…Έλž€μƒ‰ 동그라미가 μ‰Ό 없이 μ™Όμͺ½μ—μ„œ 였λ₯Έμͺ½μœΌλ‘œ μ›€μ§μ΄λŠ” μ• λ‹ˆλ©”μ΄μ…˜μ΄ λ§Œλ“€μ–΄μ‘ŒμŠ΅λ‹ˆλ‹€.
λ§Œμ•½ κ²Œμž„μ„ λ§Œλ“€ λ“― 원을 ν΄λ¦­ν•˜λ©΄ λ©ˆμΆ”λŠ” 이벀트λ₯Ό λ§Œλ“€κ³  μ‹ΆμœΌμ‹ κ°€μš”? κ·Έλ ‡λ‹€λ©΄ requestAnimationFrame을 μ·¨μ†Œν•΄μ£Όμ‹œλ©΄ λ©λ‹ˆλ‹€! κ·Έ 방법은 cancleAnimationFrame λͺ…령을 λΈŒλΌμš°μ €μ— λ‚΄λ €μ£Όμ‹œλŠ” κ²λ‹ˆλ‹€. μ•„λž˜μ™€ 같이, 쑰건을 μΆ”κ°€ν•΄μ£Όμ„Έμš”.
document.querySelector(".circle").addEventListener("click", function () { if(touch) { window.cancelAnimationFrame(touch); touch = null; } else { go(); } });
μ΄λ ‡κ²Œ κ°„λ‹¨νžˆ, μ›€μ§μ΄λŠ” μ• λ‹ˆλ©”μ΄μ…˜μ„ λŠκΉ€ 없이 λ§Œλ“€κ³  또 μ›ν•œλ‹€λ©΄ λ©ˆμΆ”κ²Œλ„ ν•˜λŠ” μž‘μ—…μ„ μ™„λ£Œν–ˆμŠ΅λ‹ˆλ‹€. λ²ˆμ™Έλ‘œ λ§Œλ“€κ³  ν™•μΈν•΄λ³΄μ‹œλ©΄ μ•„μ‹œκ² μ§€λ§Œ, μ• λ‹ˆλ©”μ΄μ…˜μ΄ μ›€μ§μ΄λŠ” μƒνƒœμ—μ„œ λ‹€λ₯Έ 창으둜 μ΄λ™ν–ˆλ‹€κ°€ λ‹€μ‹œ λŒμ•„μ™”μ„ λ•Œ, μž μ‹œ λ©ˆμ·„λ˜ μ• λ‹ˆλ©”μ΄μ…˜μ΄ λ‹€μ‹œ μ›€μ§μ΄λŠ” 것을 ν™•μΈν•˜μ‹€ 수 μžˆμ„ κ²λ‹ˆλ‹€. μ΄λ ‡κ²Œ requestAnimationFrame은 λŠκΉ€λ„ μ—†κ³ , 배터리도 μ•„κ»΄μ£ΌλŠ” 쒋은 ν•¨μˆ˜μž…λ‹ˆλ‹€ :)

3. requestAnimationFrameλ₯Ό μ‚¬μš©ν•  수 μ—†λ‹€λ©΄?

ν˜Ήμ‹œ requestAnimationFrame ν•¨μˆ˜λ₯Ό μ΄μš©ν•˜κΈ° μ–΄λ €μš΄κ°€μš”?
requestAnimationFrame ν•¨μˆ˜λŠ” μ•žμ„œ 배운 setTimeout ν•¨μˆ˜μ™€ setInterval ν•¨μˆ˜μ— λΉ„ν•΄ μ΅œκ·Όμ— λ§Œλ“€μ–΄μ§„ ν•¨μˆ˜μž…λ‹ˆλ‹€. λ”°λΌμ„œ 이 ν•¨μˆ˜λ₯Ό μ§€μ›ν•˜μ§€ μ•ŠλŠ” λΈŒλΌμš°μ €μ—μ„œλŠ” λΈŒλΌμš°μ € μ΄μš©ν˜„ν™© λ³΄λŸ¬κ°€κΈ° 이용이 μ–΄λ €μšΈ 수 μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ λͺ‡λͺ‡ λΈŒλΌμš°μ €λŠ” requestAnimationFrame이 μ•„λ‹Œ λ‹€λ₯Έ μ΄λ¦„μœΌλ‘œ ν•¨μˆ˜λ₯Ό μ •μ˜ν•΄ 놓아 μ‚¬μš©μžμ—κ²Œ ν˜Όλ™μ„ μΌμœΌν‚€κΈ°λ„ ν•©λ‹ˆλ‹€.
window.requestAnimationFrame = (function(callback) { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60); }; })();
λ‹€ν–‰νžˆ, 이λ₯Ό 극볡할 방법이 μžˆμŠ΅λ‹ˆλ‹€. μƒλ‹¨μ˜ μ½”λ“œλ₯Ό μž‘μ„±ν•΄ λ„£μœΌμ‹œλ©΄ μΌκ΄„μ μœΌλ‘œ requestAnimationFrameμ΄λΌλŠ” μ΄λ¦„μœΌλ‘œ ν•΄λ‹Ή κΈ°λŠ₯을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
Β