requestAnimationFrame(rAF)은 웹 애니메이션을 최적화하기 위한 JavaScript API이다.
브라우저의 화면 갱신 주기(repaint)에 맞춰 애니메이션 코드를 실행시켜주는 메서드로 브라우저가 다음 repaint를 수행하기 전에 지정된 콜백 함수를 실행하도록 요청한다.
rAF는 브라우저의 repaint 주기에 딱 맞게 함수가 실행되어 프레임 드랍(frame drop)이 일어나지 않도록 도와주는 역할을 한다.
일반적으로 1초에 60번(60FPS) 실행되지만 사용자의 디스플레이 주사율(Hz)에 따라 달라질 수 있다.
60Hz 기준 1초에 60개의 프레임을 만들기 위해 1000ms / 60FPS = 16.6ms 간격으로 콜백 함수가 호출된다.
💡 용어 설명
- FPS(Freames Per Second): 초당 프레임 수를 의미한다. 화면에 표시되는 이미지가 1초에 몇 번 갱신되는지를 측정하는 단위이다.
- Hz(Hertz): 모니터 재생률(refresh rate)을 나타내는 단위로 모니터 화면이 1초에 몇 번 새로고침되는지를 의미한다.
FPS와 Hz는 서로 다른 개념이지만 밀접한 관련이 있다. 컴퓨터가 생성하는 FPS가 모니터의 Hz보다 높더라도 실제로 볼 수 있는 최대 프레임 수는 모니터의 Hz에 제한된다.
예를 들면 게임이 120FPS로 실행되더라도 60Hz 모니터에서는 초당 60 프레임만 볼 수 있다.
최적의 경험을 위해서는 높은 FPS를 생성할 수 있는 하드웨어와 그것을 표시할 수 있는 높은 Hz의 모니터가 필요하다.
백그라운드 동작 중지: 페이지가 비활성화 상태(다른 탭 이동, 브라우저 최소화 상태)일 때 애니메이션이 자동으로 중지되어 CPU 리소스와 배터리 수명을 절약한다.
디스플레이 주사율에 최적화: 사용자의 모니터 주사율에 맞게 실행된다. ex) 144Hz 모니터를 사용하는 경우 rAF는 1초에 최대 144번 호출되어 더 부드러운 애니메이션을 제공한다.
별도의 애니메이션 프레임 큐 사용: 일반적인 Task Queue가 아닌 Animation Frame Queue에서 처리되어 실행 지연을 줄인다.
불필요한 프레임 생성 방지: 브라우저의 갱신 속도에 맞춰 애니메이션이 실행되어 불필요한 프레임이 생성되지 않는다.
프레임에 의존적: 사용자 모니터 주사율에 맞게 실행되어 정확한 타이밍 조절이 어렵다.
브라우저 지원: 현대 브라우저에서는 모두 지원하지만, 오래된 브라우저에서는 벤더 프리픽스(vendor prefix)가 필요하거나 폴리필(polyfil)이 필요할 수 있다.
💡 용어 설명
- 벤더 프리픽스(vendor prefix): 브라우저 제조사가 실험적 기능이나 비표준 CSS 속성을 자신들의 브라우저에 도입할 때 사용하는 접두사이다.(
-webkit-
,-moz-
등)- 폴리필(polyfil): 최신 웹 기능을 지원하지 않는 구형 브라우저에서도 해당 기능을 사용할 수 있게 해주는 코드 조각이다.
브라우저는 애니메이션 프레임을 출력할 때 마다 rAF에 등록된 콜백 함수들을 비동기로 호출한다.
rAF 콜백 함수는 Animation Frame Queue에 추가되어 다음 화면 갱신 시 처리된다.
브라우저의 렌더링 과정(JS 실행 ➔ 스타일 계산 ➔ 레이아웃 ➔ 페인트 ➔ 컴포지팅)에서 rAF 콜백은 프레임 시작 시 실행되도록 보장한다.
Animation Frame Queue는 렌더링 과정의 일부로 처리된다. 이벤트 루프 순서에서는 Microtask Queue를 처리 후, 렌더링 단계에서 rFA 콜백이 실행된다.
Animation Frame Queue가 Task Queue보다 우선순위가 높다기보다는, 렌더링 과정의 일부로 처리된다.
💡 컴포지팅이란?
웹 페이지의 여러 부분을 별도의 레이어로 분리하고 이를 개별적으로 래스터화(픽셀화)한 후, 별도의 컴포지터 스레드에 이들을 하나의 페이지로 결합하는 기술이다.
간단하게 설명하면 여러 이미지를 하나로 합쳐 최종 화면에 표시하는 과정이다.
- 컴포지팅의 작동 방식
- 레이어 분리: 브라우저는 웹 페이지의 요소들을 여러 레이어로 분리한다.
- 개별 래스터화: 각 레이어를 별도로 래스터화(비트맵으로 변환)한다.
- GPU 활용: 이 레이어들은 주로 GPU에 저장되어 처리된다.
- 레이어 결합: 컴포지터 스레드에서 이 레이어들을 올바른 순서로 결합하여 최종 화면을 생성한다.
이러한 별도의 큐 처리 방식 덕분에 rAF는 브라우저의 repaint 주기에 맞게 실행되어 프레임 드랍이 일어나지 않도록 도와주는 역할을 한다.
requestAnimationFrame(callback);
콜백 함수에는 requestAnimationFrame()
이 콜백 함수들의 실행을 시작할 시점을 나타내는 performance.now()
에 의해 반환되는 것과 유사한 DOMHighResTimeStamp
단일 인수가 전달된다.
💡 DOMHighResTimeStamp이란?
브라우저의performance.now()
메서드가 반환하는 것과 같은 형태의 시간 값이다.
- 밀리초 단위로 표현되는 숫자 값이다.
- 소수점 이하까지 포함하여 매우 정밀한 시간을 나타낸다.
requestAnimationFrame
의 인수에서는 애니메이션을 시작하는 시점의 시간 값이다.
이 값을 cancelAnimationFrame()
에 전달해 콜백 요청을 취소할 수 있다.
const animationFn = (timeStamp) => {
console.log(`애니메이션이 시작된 시간: ${timeStamp}ms`);
callCount++;
box.style.transform = `translateX(${xPosition}px)`;
xPosition += 5;
if (timeStamp > TWO_SECOND) {
// 2000ms 지나면 애니메이션 종료
console.log(`${CURRENT_HZ}Hz에서 2초 동안 animationFn 호출 횟수: ${callCount}`);
console.log(`2000ms / ${CURRENT_HZ} = ${TWO_SECOND / CURRENT_HZ}`);
cancelAnimationFrame(animationId);
return;
}
animationId = requestAnimationFrame(animationFn);
};
requestAnimationFrame(animationFn);
위 두 예시에서 볼 수 있듯이 디스플레이 주사율에 따라 애니메이션의 부드러움과 함수 호출 횟수가 크게 달라진다.
const animateFn = (timestamp) => {
if (!lastTime) {
// 초기 lastTime 갱신
lastTime = timestamp;
}
const elapsed = timestamp - lastTime;
// 경과 시간에 비례하여 이동 거리 계산
const delta = (elapsed / 1000) * speed;
position += delta;
box.style.transform = `translateX(${position}px)`;
lastTime = timestamp;
requestAnimationFrame(animateFn);
};
requestAnimationFrame(animateFn);
위와 같이 프레임 속도와 상관 없이 타임스탬프를 활용하여 경과 시간을 통해 일정한 속도로 애니메이션을 구현할 수도 있다.
실행 타이밍: rAF는 브라우저의 프레임 주기에 맞춰 실행되지만, 타이머 함수는 단순히 지정된 시간 간격으로 실행된다.
최적화: rAF는 브라우저의 렌더링 프로세스와 동기화되어 프레임 드랍을 방지하지만, 타이머 함수는 프레임을 고려하지 않는다.
백그라운드 동작: rAF는 페이지가 비활성화되면 실행이 중지되지만, 타이머 함수는 계속 실행된다.
권장 사용처: rAF는 애니메이션에 최적화되어 있고, 타이머 함수는 고정 시간 간격 작업에 적합하다.
자바스크립트의 싱글 스레드 특성: 자바스크립트는 싱글 스레드로 동작하기 때문에 콜 스택에 다른 작업이 있으면 타이머 콜백의 실행이 지연될 수 있다.
이벤트 루프의 작동 방식: 타이머 콜백은 이벤트 루프의 Task Queue에 추가되며 콜 스택이 비어있을 때만 실행된다. 따라서 다른 작업이 오래 걸리면 타이머의 실행이 지연된다.
브라우저의 내부 최적화: 브라우저는 성능과 배터리 수명을 위해 백그라운드 탭의 타이머 실행 빈도를 줄이는 등의 최적화를 수행할 수 있다.
프레임 동기화 부재: 타이머 함수는 브라우저의 렌더링 주기와 동기화 되지 않아 프레임 중간에 실행될 수 있으며, 이로 인해 프레임 드랍이 발생할 수 있다.
requestAnimationFrame(rAF)은 웹 애니메이션을 최적화하기 위한 JavaScript API로, 브라우저의 화면 갱신 주기에 맞춰 애니메이션 코드를 실행시켜 부드러운 애니메이션을 구현할 수 있게한다.
브라우저의 repaint 주기에 맞춰 실행되어 프레임 드랍을 방지한다.
일반적으로 1초에 60번(60FPS) 실행되지만, 사용자의 디스플레이 주사율에 따라 달라진다.
페이지가 비활성화되면 실행이 중지되어 리소스를 절약한다.
별도의 Animation Frame Queue를 사용하여 실행 지연을 최소화한다.
setTimeout
, setInterval
과 같은 타이머 함수와 달리 브라우저의 렌더링 프로세스와 동기화되어 더 부드러운 애니메이션을 제공하며, 복잡한 애니메이션이나 세밀한 제어가 필요한 경우 CSS 애니메이션보다 더 나은 선택이 될 수 있다.
1. transform
, opacity
속성 우선 사용
GPU 가속: transform
, opacity
속성은 브라우저의 컴포지팅 단계에서 GPU에 의해 처리될 수 있다. 이는 CPU에서 처리되는 일반 속성(width
, height
, top
, left
등)보다 훨씬 효율적이다.
레이아웃 재계산 방지: left
, top
과 같은 속성을 변경하면 브라우저는 요소의 위치와 크기를 다시 계산하고 다시 렌더링해야 한다. 반면 transform
은 레이아웃에 영향을 주지 않고 컴포지팅 단계에서만 변경이 일어나므로 더 효율적이다.
2. 불필요한 DOM 접근 최소화
DOM 접근은 JavaScript 실행 중 가장 비용이 많이 드는 작업 중 하나이다.
DOM 접근 비용: DOM에 접근하는 것은 JavaScript 객체에 접근하는 것보다 훨씬 느리다. 브라우저는 JavaScript 엔진과 렌더링 엔진 사이를 오가야 하기 때문이다.
참조 저장: DOM 요소에 반복적으로 접근하는 대신, 변수에 참조를 저장하고 그 변수로 작업하면 성능이 향상된다.
일괄 처리: 여러 DOM 변경을 개별적으로 하지 않고 일괄 처리하면 리플로우(reflow)와 리페인트(repaint)의 횟수를 줄일 수 있다.
3. 타임스탬프를 활용한 애니메이션 속도 일정하게 유지
requestAnimationFrame의 콜백 함수는 타임스탬프를 매개변수로 받는다. 이를 활용하면 프레임 속도와 상관없이 일정한 속도로 애니메이션을 구현할 수 있다.
시간 기반 애니메이션: 프레임 간 경과 시간을 계산하여 움직임의 양을 조절함으로써 다양한 디스플레이 주사율에서도 일정한 속도로 애니메이션을 구현할 수 있다.
프레임 독립적 움직임: 60Hz 모니터와 144Hz 모니터에서 동일한 속도로 애니메이션이 실행될 수 있도록 보장한다.
Window: requestAnimationFrame() method - MDN
🌐 웹 애니메이션 최적화 requestAnimationFrame 가이드
애니메이션을 그린다고요? setTimeout 싫어요! requestAnimationFrame 좋아요!
이딴 게.. 타이머? 자바스크립트의 런타임과 Event Loop
requestAnimationFrame 메서드에 대한 탐구
素晴らしいブログ記事ですね!野球ゲームの魅力やおすすめのサイトについて詳しく説明されていて、とても参考になりました。特に、リアルな体験や戦略的要素が強調されている点が印象的でした。
私も最近、 https://baseballgamesjp.org/ を訪れて、最新の野球ゲーム情報をチェックしました。このサイトは、さまざまなプラットフォームのゲームを網羅していて、レビューや攻略情報も豊富です。特に、プレイヤーの成長システムについての情報が役立ちました。
また、他のサイトもチェックしてみたいと思います。特に、GameSpotやIGNのレビューは信頼性が高いので、今後のゲーム選びに役立てたいです。これからも、野球ゲームの世界を楽しんでいきたいと思います。素晴らしい情報をありがとうございました!
This blog is quite useful! The requestAnimationFrame(rAF) function is essential for optimizing animations in the browser, ensuring smooth and efficient rendering. Unlike setTimeout or setInterval, rAF synchronizes with the display refresh rate, reducing unnecessary calculations and improving performance. Just like in Geometry Dash, where timing and precision are key to success, rAF helps maintain fluid motion by preventing frame drops. Have you experimented with it in your projects?
I used it to make a virtual hug for my mom who lives across the country, and I'm not going to lie, we both teared up a little. There's something so comforting about seeing a hug, even if it's AI-generated. In today's world where we're often physically apart from loved ones, ai-hug.org (https://ai-hug.org) bridges that gap in a way that texts and calls just can't.
The process is super easy too! Just upload photos and watch as the AI creates these surprisingly touching moments.
Need a good laugh? Check out https://funny-jokes.co for daily clean jokes that'll make your day! Perfect for sharing with friends and family - there's always something new to discover and smile about! 😊
素晴らしいウェブサイト https://emojimix.online/ を発見しました!2つの絵文字を組み合わせて新しいユニークな絵文字を作れる対話型プラットフォームです。絵文字好きとして、デジタルコミュニケーションに楽しいひねりを加えられて、とても楽しんでいます。使い方も簡単で、可能性は無限大です。ウェブでもモバイルアプリでも、絵文字で創造性を発揮するのに最適なツールです。強くおすすめします!
I do believe this is an excellent website. I stumbled upon it I may revisit once again since I saved as a favorite it. https://wwwsnaptik.com
I usually use Morse Code Translator to practice morse code, and use it to translate some interesting symbols
좋은 글 감사합니다!
[오타]
컴포지팅의 작동 방식
레이어 분리: 브라우저는 웹 페에지의 요소들을 여러 레이어로 분리한다. -> 웹 페이지
개별 래스터화: 각 레이어를 별도로 래스터화(배트맵으로 변환)한다. -> 비트맵