에듀테크 프로젝트 대시보드
requestAnimationFrame
requestAnimationFrame(이하 rAF)은
브라우저가 다음 화면을 그리기 직전에 딱 한 번 불러주는 콜백이다. 콜백은 현재 시각(타임스탬프)을 인자로 받으므로,
그 시각으로 실제 경과 시간을 계산해 위치를 정하면 프레임이 몇 번 불렸든 항상 정확한 자리에 그려진다.
반대로 "콜백 한 번 = 고정 걸음 한 칸"으로 짜는 초보적인 setInterval
애니메이션은 콜백이 밀리면 그만큼 뒤처진다. 아래에서 직접 재생하고, 메인 스레드를 블로킹해 그 차이를 확인해 보자.
파란 기준선과 초록 rAF 점은 항상 겹친다. 매 콜백마다 timestamp - startTime으로
실제 경과 시간을 다시 계산해 위치를 정하기 때문에, 콜백이 늦게 불려도 "늦게 부른 만큼" 더 멀리 이동해
제자리를 찾는다.
rAF는 브라우저가 실제로 다음 화면을 그리기 직전에 호출된다. 대부분 모니터가 60Hz라 약 16.7ms 간격이 되고, 탭이 백그라운드로 가면 브라우저가 rAF 호출 자체를 멈춰 배터리를 아낀다. 반면 setInterval은 화면 주사와 무관하게 그냥 정해진 시간마다 울리는 알람일 뿐이다.
빨간 점(setInterval)은 "콜백이 불릴 때마다 한 칸"만 이동한다. 메인 스레드가 1.5초간 막히면 그 사이 예정됐던 호출들이 대부분 사라지고 딱 1~2번만 불리므로, 블로킹이 끝나도 실제 경과 시간만큼 따라잡지 못하고 계속 뒤처진 채로 남는다.
핵심: 애니메이션 로직은 "몇 번 호출됐는가"가 아니라 "얼마나 시간이 지났는가"를
기준으로 짜야 한다. 게임 엔진에서도 이를 delta time 기반 이동이라 부르며,
프레임이 들쭉날쭉해도(고사양 PC의 144fps든 저사양의 30fps든) 물체의 실제 이동 속도는 동일하게 유지된다.
초 단위 시계 표시, 폴링 등 화면을 부드럽게 그릴 필요가 없는 반복 작업에는 여전히 적합하다. 하지만 캔버스·CSS 애니메이션처럼 눈에 보이는 움직임을 그릴 때는 rAF가 화면 주사율에 맞춰 부드럽고, 불필요한 렌더링(화면에 안 그려질 프레임)을 만들지 않아 항상 더 낫다.
콜백이 16.7ms 예산을 넘기면 그 프레임은 이미 밀린 것이고, 브라우저는 다음 리페인트 때 다시 한 번만
호출한다 — 밀린 프레임을 몰아서 여러 번 호출해주지 않는다. 그래서 콜백 내부는 항상 가볍게 유지하고,
무거운 계산은 Web Worker로 분리하는 것이 정석이다.