[JS] 자바스크립트가 비동기 작업을 처리하는 방법(FEAT. 이벤트 루프, 태스크 큐)

apro_xo·2022년 11월 19일
2
post-thumbnail

1. 자바스크립트는 싱글 스레드

자바스크립트는 제목에서도 알 수 있는 것 처럼 싱글 스레드이다.
싱글 스레드라는 것은 쉽게 얘기하면 프로세스로 부터 할당 받은 일을 처리할 수 있는 녀석(?)이 하나 밖에 없다는 것이다. 상식적으로는 하나의 스레드가 여러 일을 처리하려면 동기적으로 일을 처리할 수 밖에 없다. 한 번에 하나의 일만 하는 것이다(run to completion).

하지만 우리는 자바스크립트를 통해 비동기 동작을 구현할 수 있다.
알기 쉬운 예로 setTimeout()을 사용하여 비동기 동작을 구현 할 수 있다.

📌 싱글 스레드인 자바스크립트가 비동기 동작을 어떻게 처리할 수 있을까?

2. 실행 환경에게 help!(FEAT. web api)

자바스크립트의 실행 환경은 host 즉, 웹 브라우저다.

크롬 브라우저에는 자바스크립트를 실행하기 위한 V8 자바스크립트 엔진이 존재한다.

V8 엔진에는 실행 컨텍스트를 담는 콜 스택(호출 스택), 크기가 동적으로 변하는 값들의 참조 값을 갖고 있는 힙(heap)이 존재한다.

setTimeout(()=> {
  alert("time out!");
}, 1000);

console.log("hello");

위와 같은 코드를 V8 엔진에서 파싱할 때, setTimeout()에 의한 실행 컨텍스트를 콜스택에 저장, console.log()에 의한 실행 컨텍스트를 콜스택에 저장한다.

이 상황에서 브라우저가 자바스크립트가 실행이 될 때 비동기 작업을 해야하는 타이밍 즉, setTimeout()을 실행해야 할 때가 되면 브라우저는 web api에게 이 작업을 넘긴다.
당연하게 setTimeout() 뿐만 아니라, API 요청과 같은 비동기 동작 또한 마찬가지다.

이렇게 해서 web api가 네트워킹도 대신 처리해주고, setTimeout과 같은 메서드도 대신 처리해준다.

3. 콜 스택과 태스크 큐(FEAT. 이벤트 루프)

setTimeout(()=> {
  alert("time out!");
}, 1000);

위 코드가 실행된다고 가정하면, 1초를 세어 주는 것은 web api가 대신 해주고, alert()를 띄워주는 것은 콜 스택이 담당해야한다.

하지만 콜 스택도 놀고만 있지는 않을 것이다. 비동기 작업을 web api가 처리하는 동안 콜 스택 또한 실행 컨텍스트로 쌓인 어떠한 일을 계속 수행하고 있었을 것이다.
갑자기 web api에서 완료된 비동기 작업을 콜 스택이 수행하기에는 무리가 있을 것이다.

따라서 web api는 비동기 처리가 끝난 작업을 태스크 큐에 임시 저장한다.🔥

태스크 큐에 들어간 작업은 콜 스택이 모든 작업을 끝마칠 때 까지 대기하다가 콜 스택이 비면(empty) 콜 스택으로 넘어가 작업이 수행된다.

3-1. 이벤트 루프

콜 스택이 비었는지 관찰하는 관찰자

콜 스택이 비었는지 확인하고 비었다면 태스크 큐에 알려주는 역할이 필요한데,
이를 이벤트 루프가 수행한다.

태스크 큐에 있는 일을 콜 스택으로 넘길 타이밍을 관찰하다가 콜 스택이 비면 이벤트 루프가 태스크 큐에 있는 일을 콜 스택으로 넘긴다.

자바스크립트가 브라우저에서 이런 방식으로 동작한다.

4. 마이크로태스크큐

위의 예시에서 setTimeout이 태스크 큐로 이동한다고 했다. 그럼 마이크로태스크큐는 무엇인가?

2개의 큐 모두 비동기 처리를 담당하는 것은 같지만 어떤 것을 실행하느냐에 따라 어디로 들어가는지가 달라진다.

📌 태스크 큐(매크로태스크큐)에 들어가는 아이들

setTimeout, setInterval, setImmediate, UI렌더링 ....

📌 마이크로태스크 큐에 들어가는 아이들

process.nextTick, Promise, Object.observe ...

4-1. 먼저 실행되는건 누구?

마이크로태스크 큐에 있는 아이가 먼저 실행된다.
이벤트 루프는 콜 스택이 비면 먼저 마이크로태스크 큐에서 대기하고 있는 작업을 가져와 실행한다. 이후 마이크로태스크 큐가 비면 태스크 큐에 대기하고 있던 작업들을 가져와 실행한다.

아래의 코드를 실행해보면

console.log('콜 스택!');
setTimeout(() => console.log('태스크 큐!'), 0);
Promise.resolve().then(() => console.log('마이크로태스크 큐!'));

마이크로태스크 큐의 작업이 먼저 실행된다. Promise가 먼저 실행됨을 알 수 있다.

5. 동시성

자바스크립트는 기본적으로 한 번에 하나의 일을 처리하지만, 실행 환경의 도움을 받아 여러 작업이 한 번에 처리되는 것 처럼 보이는데, 이를 동시성이라고 한다.

병렬과는 다르다. 자바스크립트가 동시성을 가진다고 해서 실제로 동시에 모든 작업이 실행되는 것은 아니다. 이를 병렬이라고 부른다.

하지만 자바스크립트는 그것은 아니기 때문에 병렬이라고 볼 수 없고, 동시성을 가진다고 볼 수 있다.

profile
유능한 프론트엔드 개발자가 되고픈 사람😀

0개의 댓글