Event Loop의 용어나 동작 원리 그리고 requestAnimationFrame에 대해 어설프게 알고 있어 정리하고자 합니다.
이름에서 알 수 있듯이, JS가 처리해야 하는 task가 있는지 끊임없이 체크하고 실행시키는 Loop입니다
JS는 Single Thread입니다. JS는 Single Thread에서 Non-blocking을 구현하기 위한 방법으로 Event Loop를 사용합니다. Non-blocking이 뭐길래 구현해야 할까요?
우선 블록킹(blocking)은 어떤 코드가 CPU를 독점적으로 사용하여 다른 코드의 실행을 막는 것을 말합니다.
이와 반대로 논 블록킹(non-blocking)은 코드를 실행해도 다른 코드를 실행할 수 있는 것을 말합니다.
하지만 CPU가 코드를 실행하면 항상 블록킹 상태를 유발합니다. 왜냐면 CPU는 코드 하나만 실행하기 때문입니다. 그러면 논 블록킹은 뭘까요?
기준 시간안에 다른 코드를 실행할 수 있다면 논 블록킹이라고 부릅니다. 예를 들어 기준이 200ms라면 해당 시간안에 코드를 실행하고 다음 코드를 실행한다면 논 블록킹 코드입니다.
한번에 여러가지 일을 수행하는 것처럼 보이는 효과가 있습니다.
결국 Event Loop는 Non-blocking을 구현함으로써 많은 일을 멈추지 않고 한번에 할 수 있게 됩니다.(병렬성)
우선 task queue와 microtask queue를 알아야 합니다.
이벤트 콜백 혹은 Web API와 같은 것을 말합니다.
<script src="...">
setTimout
의 콜백과 같은 Web APImouseEvent
와 같은 Eventtask queue와 비슷하지만, microtask queue는 task 실행 전에 모두 실행됩니다. 즉, Event loop의 한 주기 동안 모든 microtask을 실행하고 종료한 후에 다음 주기로 넘어가는 특징이 있습니다.
특정 상황(setTimeout
, Promise
)을 가정하고 설명하겠습니다.
setTimeout
을 만나면 콜백을 task queue에 추가하고 call stack이 비었을 때 실행합니다. call stack이 비었을 때 실행되기에 setTimeout
의 시간 인자는 가장 빠르게 실행할 수 있는 최소 시간만을 의미합니다.
또한, task queue의 task가 많아서 Event loop의 한 주기를 지난다면 다음 주기에 실행됩니다.
Promise
을 만나면 해당 resolve 코드를 microtask queue에 등록합니다. call stack이 비었을 때 실행합니다.
등록된 microtask queue가 많다면 taskqueue를 다 실행하여 종료하기 전까지 제어권을 다른곳으로 넘기지 않습니다. 이와 같은 이유로 microtask queue에 많은 코드를 넣는다면 성능상에 문제가 있을 수 있습니다.
다음 리페인트 전에 호출되는 함수입니다. 1초에 60회(60fps)의 주기를 갖습니다.
화면 애니메이션이나 요소의 위치변화와 같은 렌더링 로직은 setInterval
으로 하지말고 rAF로 해야합니다. setInterval
은 call stack이 비워져야만 실행되기 때문에 1 프레임(16.6ms)에 여러번 실행되거나 실행되지 않는 경우가 발생합니다. 이와 다르게 rAF는 1프레임에 1회만 실행되기에 자연스러운 애니메이션이나 렌더링 과정을 만들 수 있습니다.
참고
JavaScript의 queueMicrotask()와 함께 마이크로태스크 사용하기 - MDN
Event Loop - MDN
이벤트 루프, 넌 누구냐
어쨌든 이벤트 루프는 무엇입니까? | Philip Roberts | JSConf EU
Jake Archibald: 루프 속 - JSConf.Asia
76코드스피츠