"프레임워크 없는 프론트엔드"라는 책을 읽다가 requestAnimation라는 메소드를 만나보게 되었다. 이번에 처음 본건 아닌데 이참에 정리해보면 좋을거 같다.
window.requestAnitmation(callback);
callback 함수는 반드시 자기 자신을 가르켜야 한다.
window.requestAnimationFrame()
메소드는 브라우저에게 수행하기 원하는 애니메이션을 알리고 리페인트가 진행되기 전 해당 애니메이션을 업데이트하는 함수를 호출하게 한다. 즉, 리페인트 이전에 실행할 콜백을 인자로 받는다. 그런데 애니메이션의 경우, 리페인트 과정이 끝나지도 않았는데 다음 좌표로 이동하라고 애니메이션을 수행하는 경우, 애니메이션이 의도한 대로 부드럽게 움직이지 않게 된다. requestAnimationFrame은 이러한 문제를 해결해준다.
MDN 예제
const element = document.getElementById('some-element-you-want-to-animate');
let start, previousTimeStamp;
let done = false
function step(timestamp) {
if (start === undefined) {
start = timestamp;
}
const elapsed = timestamp - start;
if (previousTimeStamp !== timestamp) {
// Math.min() is used here to make sure the element stops at exactly 200px
const count = Math.min(0.1 * elapsed, 200);
element.style.transform = 'translateX(' + count + 'px)';
if (count === 200) done = true;
}
if (elapsed < 2000) { // Stop the animation after 2 seconds
previousTimeStamp = timestamp
!done && window.requestAnimationFrame(step);
}
}
window.requestAnimationFrame(step);
다른 간단한 박스 이동 예제
<body>
<div>
<div id="container" style="width: 500px; border: 1px solid">
<div
id="animate-box"
style="width: 50px; height: 50px; background: wheat"
></div>
</div>
</div>
<script>
const element = document.getElementById("animate-box");
const parentElement = document.getElementById("container");
function move(timestamp) {
const elementLocate = element.getBoundingClientRect();
const containerLocate = parentElement.getBoundingClientRect();
element.style.transform = "translateX(" + elementLocate.left + "px)";
if (
elementLocate.left <
containerLocate.width - elementLocate.width - 10
) {
requestAnimationFrame(move);
}
}
requestAnimationFrame(move);
</script>
</body>
MDN에 따르면 엣지 버전이 17 미만과 Internet Explorer는 페인트 사이클 전에 requestAnimationFrame을 확실하게 실행할 수 없다고 한다.
참고:
https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
https://blog.coderifleman.com/2016/12/02/how-to-test-request-animation-frame/