자바스크립트 엔진 : 싱글 스레드(Single thread)
브라우저에 내장된 자바스크립트 엔진은 한 번에 태스크(task) 1개만 처리하는 싱글스레드 방식으로 동작한다.
그런데 자바스크립트로 동작하는 브라우저를 보면 여러가지 일이 동시에 실행되는 상황이 나오기도 한다.
어떻게 싱글 스레드로 여러 가지 일이 동시에 실행되는 것처럼 만드는 걸까?
싱글 스레드에서 여러 가지 일이 동시에 실행되는 것처럼 보이게 하기 위해서는 이벤트 루프(Event Loop)가 필요하다.
이벤트 루프는 웹 브라우저에 내장된 기능.

브라우저 환경 : 태스크 큐, 이벤트 루프
1.태스크 큐
setTimeout 이나 setInterval 같은 비동기 함수의 콜백 함수, 이벤트 핸들러가 일시적으로 보관되는 영역.
2.이벤트 루프
이벤트 루프는 콜 스택에 현재 실행 중인 실행 컨텍스트가 있는지, 태스크 큐에 대기중인 함수(콜백 함수, 이벤트 핸들러..)가 있는지 반복해서 확인한다. 콜스택이 비어 있고 태스크 큐에 대기중인 함수가 있다면 이벤트 루프는 순차적으로 태스크 큐에 대기 중인 함수를 콜스택으로 이동시킨다. 이때 콜 스택으로 이동한 함수는 실행된다.
이처럼 이벤트 루프는 스택이 비워지고 나서 태스크 큐에 있는 함수를 순차적으로 콜 스택으로 넣어주기 때문에,
settimeout 콜백 함수는 콜스택에 console.log("HI") 가 있다면 그것이 실행 된 이후, 콜 스택이 비워졌을 때 태스크 큐로 이동되어 실행 된다.
- 예시를 통해 다시 설명
3초뒤에 콘솔로그를 출력하는 setTimeout을 호출했다.
setTimeout()은 콜스택에서 지워지고, 그 안의 내용을 토대로 웹 api가 타이머를 시작한다.
이 타이머가 시작되는 와중에도 자바스크립트엔진은 돌아간다. 즉 병렬적으로 이루어진다.
그리고 지정된 3초가 지나면 웹 api는 *task que에 실행할 콜백을 집어 넣는다.
//que는 FIFO(first in first out).
//que의 api로는 add와 remove가 있는데, add하면 뒤에 숫자가 들어가지만 remove하면 제일 처음에 들어왔던 순서대로 나가게 된다.
태스크 큐에 들어있는 콜백함수의 실행시점.
태스크큐와 콜스택을 관찰하고 있는 이벤트 루프라는게 있다.
이벤트 루프는 계속 빙글빙글 돌면서 콜스택과 태스크큐를 관찰한다.
콜스택에 일이 남아있으면 콜스택이 비워질 때까지 기다린다.
그리고, 콜스택이 비어서 자바스크립트엔진이 더 이상 일을 하고 있지 않을때,
태스크큐에 있는 작업을 콜스택으로 보낸다.
그러면 그 때 자바스크립트 엔진이 setTimeout에서 요청했던 작업을 실행하게 되는 것.
다른 웹 에이피아이들도 마찬가지.
클릭 이벤트 발생했을때 그것을 task queue 안에 넣는 것, 그리고 콜스택이 비면 이벤트 루프를 통해 거기로 들어가는 것.
* 태스크 큐에 있는 이벤트는 한번에 하나씩만 보낸다. 콜스택에 있는 그 콜백이 다 끝나면 다시 태스크큐에 남아있는 다른 이벤트 하나를 보내는 것.
* 콜스택에서 지금 수행중인 것은 끝날때까지 보장이 된다. 이벤트루프가 콜스택에서 처리중인 일이 끝날 때까지 그 앞에서 기다린다.
어떤 시간이 아주 오래걸리는 작업이 진행중이면 다른 곳을 클릭해도 작동하지 않을 때의 이유입니다.
Task que + Microtask que, Animation Frames.
Microtask Queue는 프로미스 콜백. 프로미스가 다 수행이 되고나면 그 다음에 등록한 then의 콜백함수, 그리고 Mutation observer 웹 api가 들어갑니다. 마이크로태스크 큐는 이벤트루프가 그 곳에 머물러 있는 동안 다른 then이나 mutation obserer 콜백이 들어오면 그것도 다 처리하고, 처리하기 전까지는 그곳에서 움직이지 않습니다. 그리고 다 처리해야 이벤트루프는 다시 순회를 시작합니다.
Animation Frames 는 주기적으로 브라우저에서 우리가 요소들을 움직이거나 애니메이션 동작을 할 때 브라우저를 업데이트 해줘야 하기 때문에, 그 일련의 과정들을 브라우저 렌더링과 관련된 Task를 받는 Queue. Animation Frames에는 Request animation frame 이라는 api가 있는데 이 api를 통해서 콜백 등록해 놓으면 다음에 브라우저가 업데이트 되기 전에 콜백을 실행해줍니다.
브라우저에게 수행하기를 원하는 애니메이션을 알리고 다음 리페인트가 진행되기 전에 해당 애니메이션을 업데이트하는 함수를 호출하게 합니다. 이 메소드는 리페인트 이전에 실행할 콜백을 인자로 받습니다.
이벤트루프는 아주아주 빠른 속도로 화면 움직임 자연스러운 속도인 초당 60프레임 16.67ms 보다 더 빠르게 돌기 때문에 animation frames에 돌때마다 갈 필요가 없습니다. 브라우저가 지정해준 속도에 따라서 얼마에 한번씩 렌더시퀀스에 들립니다. 한번 업데이트 해주고 또 다른 일들 막 처리하다가 다시 와서 한번씩 처리해주고 이런식.
- 동기적으로 실행할 수 있게 만들기
function() {
testA()
setTimout(() => {
testB()
}, 0)
}
이벤트루프의 특징(콜스택에 쌓인 함수들을 모두 실행한 이후 task que의 함수를 콜스택으로 옮기는)을 이용하면
test 함수가 실행 된 이후, 다 끝난 이후에 testB가 실행될 수 있게 할 수 있다.
참고사이트
https://developer.mozilla.org/ko/docs/Web/JavaScript/EventLoop