JavaScript/DreamCoding

RAF(Request-Animation-Frame)의 이해

느리지만 꾸준하게 2021. 7. 22. 00:59
<!DOCTYPE html>

<html lang="en">



<head>

    <meta charset="UTF-8">

    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Document</title>

    <style>

        button {

            font-size: 50px;

            cursor: pointer;

        }

    </style>

</head>



<body>

    <button>RequestAnimationFrame</button>

    <script>

        const button = document.querySelector('button');

        button.addEventListener('click', () => {

            requestAnimationFrame(() => {

                document.body.style.backgroundColor = 'beige';

            });

            requestAnimationFrame(() => {

                document.body.style.backgroundColor = 'orange';

            });

            requestAnimationFrame(() => {

                document.body.style.color = 'red';

            });

            setTimeout(() => {

                //

            }, 0);

        });

    </script>

</body>

대략적으로 이 코드를 보면 총 3가지의 리퀘스트를 보내게 되는데 첫 번째는 바디 스타일의 백그라운드 색상을 베이지로 두 번째는 바디 백그라운드 색상을 오렌지로 세 번째는 바디 색상을 레드로 변경하도록 리퀘스트를 등록해 놓았다.

그러면 이제 버튼을 클릭하면 빨간색으로 변한다. 왜 그러냐?

 

웹 APIs에서 버튼 리스너가 등록이 되었고 버튼에 이벤트가 발생하면 웹 APIs가 태스크 큐에 사용자의 콜백 함수를 등록해 놓는다. 그리고 이벤트 루프가 돌다가 태스크 큐에 있는 아이템을 콜 스택으로 가져온다.

콜 스택에서는 사용자가 등록한 이벤트 리스너의 콜백 함수가 수행이 된다. 코드 블럭 그리고 콜백 안에서 총 세 가지의 일이 있는데 리퀘스트 애니메이션 프레임의 색깔 베이지, 오렌지, 레드색깔 각각 세 개의 API를 호출 하게 된다. 리퀘스트 애니메이션 프레임라고 해서 콜백 함수를 등록해 놓고 똑같이 두 번쨰 API를 호출하면 두번째 콜백도 등록된다. 마지막으로 세 번째 리퀘스트 애니메이션 프레임을 호출하면서 콜백이 레드라고 바꾸는 문장 코드 블럭을 호출 하게되면서

큐 안에 각각 색상을 변경하는 코드들이 등록 되어져 있다. 호출한 순서대로 들어가 있다. 베이지 - 오렌지 - 레드

이런 순서로 콜백이 등록되어져 있고

 

여기서 큐의 FIFO 개념이 사용되는데, 리퀘스트 애니메이션 프레임 콜백을 등록해 놓고 클릭 리스너의 콜백이 다 끝나면 이벤트 루프가 함 돌아볼까 하고 돌다가 브라우저한테 업데이트 할 시간이 되었다라고 렌터 시퀀스에 렌더링하는 순서로 진입하게 된다. 리퀘스트 애니메이션 프레임 큐에 아이템들이 조금 있으니까 순서대로 한번 보고, 베이지 색깔 업데이트 오렌지 색깔 업데이트 최종적으로 빨간색의 코드가 적용이 된 다음에 렌더 트리로 들어가게 된다. 렌더 트리에서 레이아웃을 하고 최종적으로 빨간색이 적용된 상태에서 렌더 트리와 레이아웃이 만들어지고 페인트가 이뤄진다. 마지막에 색상을 바꾼 빨간 색깔이 이겨서 브라우저에 표기가 완료가 된 다음에 렌더링이 완료해서 다시 도는 순서가 된다.

 

 

 

 

그리고 앞에서 본 setTimeout을 원하는 콜백을 등록해 놓고 0밀리세컨드 있다가 무언가를 수행 하는 경우도 있는데 콜 스택 안에서 코드 블럭이 실행되는 순간말고 이것이 끝나면 이벤트 루프가 한 바퀴 돌고 그 다음에 코드 블럭을 실행해 달라고 말하고 싶을 때 많이 쓴다.

 

이렇게 사용자가 무언가를 변경 하고 나서 다음 차례 때 이벤트 루프가 동작 할 때 내 것을 실행해 달라고 이 때 많이 쓴다. 클릭이 발생하면 클릭에 등록된 콜백 함수가 콜 스택에서 수행되다가 다음턴 때 이벤트 루프가 한 바퀴 돌 때 실행 하고 싶을 때 setTimeout(0)를 이용하게 되면 웹 APIs한테 지금 콜백을 태스크 큐에 넣어 줘라고 해서 웹 APIs는 0밀리 세컨드 있다가 태스크 큐에 아이템을 등록하게 된다. 그리고 콜 스택이 텅텅 비어지면 setTimeout 콜백을 다시 가지고 와서 수행하게 되는데 모든 코드가 수행이 된 다음에 setTimeout에 있는 코드 블럭이 수행이 된다.

 

마지막으로 JS가 동작하는 런타임 환경에는 태스크 큐와 마이크로 태스크 큐를 이용해서 asynchronous 비동기적인 처리를 하는데 태스크 큐는 한 번에 하나씩만 가지고 오고 마이크로 태스크 큐는 들어 있는 것들 모두 다 수행할 때까지 가지고 오게 되고, 렌더는 이벤트 루프가 주기적으로 브라우저에게 UI를 업데이트 하기 위해서 자주 들러준다. 그리고 사용자가 호출한 리퀘스트 애니메이션 프레임 콜백 큐는 업데이트가 일어나기 전에 한번 돌면서 코드가 실행이 된다.