브라우저의 렌더링 주기에 맞춰 부드러운 애니메이션 효과를 제공할 수 있도록 하는 자바스크립트 내장 api
raf는 현재 해상도에 맞는 모니터의 주사율 만큼 (일반적으로 60fps) 이벤트를 발생시킴
raf 를 활용하여 reflow, repaint 최적화를 통해 성능향상 가능
백그라운드 탭으로 이동 시, 실행을 중단하기 때문에 효율적인 성능 개선에 유리함
raf의 콜백함수는 일반적으로 task Que가 아니라 우선순위가 더 높은 Animation Frames란 Que에 등록됨. 그리고 호출 스택이 비었을 때 큐에서 하나씩 가져오는 것이 아니라 Animation Frames Que 에 쌓여있는 모든 함수를 꺼내와서 실행하기에 더욱 부드러운 애니메이션 효과를 적용가능
Raf 의 동작원리를 이해하기 위해서는 우선 브라우저의 렌더링 과정을 이해할 필요가 있다.
기본적으로 브라우저는 위와 같은 단계를 거쳐서 화면에 무언가를 보여준다.
간략히 정리해서 말하자면
이 정도의 단계를 통해 최종적으로 화면 렌더링이 이루어진다고 이해할 수 있다.
화면에서 무언가 부드럽게 움직이는 것처럼 보이는 것은 사실 그렇게 보일 수 있도록 초당 수십번의 화면을 각 진행정도에 따라 연속적으로 보여주며 업데이트하기 때문에 그렇게 보이는 것이다.
여기서 모니터 주사율과 fps 개념을 접목해볼 수 있다. 보통 60hz, 120hz 같은 모니터 주사율을 쉽게 들어볼 수 있는데 이는 해당 기기가 1초동안 화면을 출력하는 빈도를 나타내는 단위인 것이다. Frame도 비슷한 의미로 그 뜻은 한 장의 사진으로 이해해도 무방하다. 그래서 fps (frame per seconds) 는 초당 보여지는 사진 장의 수를 의미하며 이는 일반적으로 60으로 맞춰진다.
(사람의 눈이 초당 60번의 장면이 변경되어 넘어갈 때 부드러운 전환이라고 인지하기 때문)
즉, 브라우저 화면상에서 무언가 부드러운 애니메이션효과를 주고자 한다면 위에 설명한 이 초당 60번의 프레임에 맞춰서 설계되어야 한다고 볼 수 있다. 쉽게 말해 16.666ms (1000ms / 60fps) 마다 주기적으로 화면 렌더링 관련 코드가 실행되어야 한다는 것.
setInterval, setTimeout 을 이용한 애니메이션 동작의 문제점
기본적으로 setTImeout, setInterval 같은 함수는 wep API 다. 이런 함수들은 실행될 때 콜스택에 쌓여서 바로 실행되는 것이 아니라 wep API 별로 따로 담기고, 각 내부의 콜백함수들은 다시 Que 로 이동되어 콜스택이 비어있게 될 때까지 대기상태가 된다.
즉, 복잡한 코드 내에서 타이머 함수 실행 후 다른 여러 함수들도 실행된다면 이후 실행된 함수들이 콜스택에 쌓여 이를 우선처리해야 하기에 Que에 있는 콜백함수들은 대기상태가 되고, 이로 인해 정확히 16.66ms 마다 실행되는 것이 아닌 중간에 blocking이 되면서 일부 프레임에 대한 화면전환 코드가 실행되지 못해 프레임 드랍이 일어나게 된다.
(이런 프레임 드랍은 곧 매끄럽지 못한 애니메이션 전환을 보여주게 된다)
정리하자면, 타이머 함수같은 Web API 들은 여러 스택이 중첩되는 상황에서는 바로 실행되지 못하기에 프레임 드랍이 일어날 수 있다. 즉 항상 일관되게 주기적으로 렌더링 주기에 맞춰 실행될 것이라는 보장을 할 수 없다.
문제해결의 방안 - requestAnimationFrame 활용
+a) raf 의 타이머 인수 활용
function animate(time) {
console.log(time); // 매 frame (raf 호출) 의 실행 시간
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);