노트

requestAnimationFrame

requestAnimationFrame

프런트엔드#browser#performance · 연결된 개념 9개

쉽게 말하면

requestAnimationFrame은 플립북의 다음 장을 그리기 직전에 '이 그림을 조금 옮겨 줘'라고 예약하는 API예요. 브라우저가 화면을 그리기 직전에 콜백을 실행해서, 바꾼 내용이 바로 그 프레임에 반영돼요.

비유가 깨지는 곳 그릴 시점만 맞춰 줄 뿐 일을 줄여 주진 않아요. 콜백이 무거우면 페인트가 밀려 INP가 나빠지고, 할 일이 없는데도 매 프레임 재예약하면 배터리를 갉아먹어요.

"다음 화면을 그리기 직전에 이 함수를 실행해 달라"고 브라우저에 예약하는 API. 콜백은 태스크 큐도 마이크로태스크 큐도 아닌 별도 목록에 들어가고, 이벤트 루프의 렌더링 단계에서 페인트 직전에 한꺼번에 실행된다.

  • 디스플레이 주사율에 맞춰 프레임당 한 번 호출된다(60Hz면 약 16.7ms마다, 120Hz면 더 자주). 콜백 인자로 타임스탬프(DOMHighResTimeStamp)를 받는데, 같은 프레임에서 실행되는 콜백은 모두 같은 값을 받는다
  • 여기서 바꾼 DOM은 같은 프레임의 렌더링에 바로 반영된다. 시각적 변경을 모아 두기 좋은 곳이라 레이아웃 스래싱을 피할 때도 쓴다
  • 콜백 안에서 다시 requestAnimationFrame을 부르면 다음 프레임으로 예약된다. 브라우저가 현재 프레임의 목록을 떠 놓고 실행하기 때문이고, 애니메이션 루프는 이 성질로 만든다
  • 탭이 안 보이면 멈추거나 크게 늦춘다. setTimeout은 백그라운드에서도 (느리게) 돈다. 화면 갱신이 목적이면 rAF를, 시간 기반 로직이면 타이머를 쓴다
  • 메인 스레드에서 실행되므로 무거운 일을 하면 그만큼 페인트가 밀려 INP(Interaction to Next Paint)가 나빠진다. 그릴 시점을 맞춰 줄 뿐 일을 줄여 주지는 않는다
function tick(t) {
  el.style.transform = `translateX(${(t / 10) % 300}px)`
  if (running) requestAnimationFrame(tick) // 매 프레임 재예약
}
requestAnimationFrame(tick)

멈추지 않는 rAF 루프

캐러셀 자동 회전이나 패럴랙스처럼 매 프레임 자신을 다시 예약하는 루프는, 화면에 아무 변화가 없을 때도 초당 60번씩 렌더링 단계를 깨운다. 한 번 한 번은 가벼워서 버벅임은 없어도 CPU(Central Processing Unit)·GPU(Graphics Processing Unit)가 절전 상태로 내려가지 못해 모바일 배터리를 갉아먹는다. 사용자가 가만히 있을 때 rAF 호출 수를 세어 보면 바로 드러난다. 정상이라면 0에 가깝다. 할 일이 없으면 재예약을 멈추고, 화면 밖이면 content-visibility의 상태 이벤트나 IntersectionObserver로 루프를 끈다.

참고: MDN — Window: requestAnimationFrame() method

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • bfcache(뒤로·앞으로 가기 캐시)

    페이지를 떠날 때 DOM과 JS 힙까지 통째로 메모리에 얼려 두었다가, 뒤로·앞으로 가기에서 그대로 되살리는 브라우저 캐시.

  • 요청 제한 (Throttling)

    요청 제한(rate limiting, throttling)은 일정 시간 동안 한 클라이언트가 보낼 수 있는 요청 수를 묶어 두는 장치다. 한도를 넘으면 429 Too Many Requests로 거절하고, 보통 Retry-After 헤더로 언제 다시 시도하면 되는지 알려 준다.

  • 콜백

    다른 함수에 인자로 넘겨서 그 함수가 대신 불러 주게 하는 함수. 동기로도, 비동기로도 불릴 수 있다.

  • 서버 렌더에서 훅이 하는 일

    서버 렌더(Server-Side Rendering, SSR)에서도 컴포넌트 함수는 실제로 호출되고, 그 안의 훅도 호출은 된다. 다만 서버에는 커밋(DOM 반영)이 없어서, 렌더 중 동기적으로 값을 계산하는 훅만 일하고 커밋 뒤에 도는 훅은 아무것도 하지 않는다. "이 훅은 클라이언트에서만 동작한다"는 말은 대개 "Effect 안의 일은 클라이언트에서만 일어난다"는 뜻이다.

  • 스트리밍 SSR

    스트리밍 SSR(Streaming Server-Side Rendering)은 서버가 페이지 전체를 다 만들 때까지 기다리지 않고, 준비된 부분의 HTML(HyperText Markup Language)부터 먼저 보내고 느린 부분은 준비되는 대로 같은 응답에 이어서 흘려보내는 렌더링 방식이다. suspense 경계가 나눔의 단위다.

보기 옵션