[JavaScript] 비동기와 이벤트루프

Dico·2021년 8월 13일
4

[JavaScript]

목록 보기
21/21
post-thumbnail

동기 & 비동기

자바스크립트는 Single Thread?

자바스크립트 엔진는 단 하나의 실행 컨텍스트 스택(Stack)을 갖는다.
한 번에 하나의 태스크만 실행할 수 있는 싱글 쓰레드(Single Thread) 방식으로 동작하는 것이다.

자바스크립트에서 함수가 실행되려면 각 함수의 "실행 컨텍스트"가 아래의 그림과 같이 Stack에 푸시되어야 한다.
자바스크립트 엔진은 단 하나의 실행 컨텍스트 Stack을 갖고 있기 때문에 동시에 2개 이상의 함수를 실행할 수가 없다.
함수들은 Stack의 최상위에서부터 차례대로(LIFO - Last in, first out) 팝되어 실행된다.

*gif 출처: https://medium.com/jspoint/how-javascript-works-in-browser-and-node-ab7d0d09ac2f

Blocking & Non-blocking

한 번에 하나의 태스크만 실행할 수 있는 싱글 쓰레드 방식이기 때문에, 처리에 시간이 걸리는 태스크를 실행할 경우, 블로킹(Blocking)이 발생되어 해당 함수의 처리가 끝날 때까지 작업이 중단된다.
이처럼 동기 처리 방식은 앞선 태스크가 종료될 때까지 이후 태스크들이 블로킹이 된다.

*그림 출처: 이웅모, 『모던 자바스크립트 Deep Dive』, 위키북스(2020)

반면, 비동기 처리 방식은 현재 실행중인 태스크가 종료되지 않은 상태라 해도 다음 태스크를 곧바로 실행하므로 블로킹이 발생하지 않는다(Non-blocking).

*그림 출처: 이웅모, 『모던 자바스크립트 Deep Dive』, 위키북스(2020)

그렇다면 어떻게 자바스크립트 엔진이 비동기 처리 방식으로 동작할 수 있는 걸까?
정답은 바로 이벤트 루프(Event Loop)에 있다!


이벤트 루프

"이벤트 루프는 자바스크립트에 동시성(concurrency)을 지원한다."

브라우저에서의 자바스크립트 작동방식

*그림 출처: https://medium.com/jspoint/how-javascript-works-in-browser-and-node-ab7d0d09ac2f

  • Web APIs: DOM관련 작업, window 관련 작업(setTimeout, setInterval 등), AJAX요청 관련 작업(fetch, XMLHttpRequest 등)과 같은 기능들을 자바스크립트와 함께 연동하여 사용할 수 있게 브라우저에서 제공하는 추가 리소스.
  • Event Loop: Stack에 현재 실행중인 실행 컨텍스트가 있는지, 그리고 callback queue에 대기 중인 함수가 있는지 반복적으로 확인한다. 만일 Stack이 비어있고, 대기 중인 함수가 있다면 이벤트 루프는 선입선출(FIFO - First in, first out) 방식으로 callback queue에 있는 함수를 Stack으로 이동시킨다. 이때 Stack으로 옮겨간 함수는 실행된다.
  • callback queue: 비동기 함수의 콜백 함수 또는 이벤트 핸들러가 일시적으로 보관되는 영역.
function one() {
  console.log("setTimeout 콜백 실행");
}

function two() {
  console.log("two 실행");
}

setTimeout(one, 0);
two();

/*
출력결과:
"two 실행"
"setTimeout 콜백 실행"
*/

위 예시를 기준으로 동작순서를 알아보자!

  1. 전역 실행 컨텍스트가 생성되고 Stack에 푸시된다.
  2. 전역 코드가 실행되어 setTimeout 함수가 호출된다. 이 때 setTimeout 함수의 함수 실행 컨텍스트가 생성되고 Stack에 푸시되어 실행된다. 그리고 Web API인 타이머 함수가 설정된다.
  3. 브라우저와 자바스크립트 엔진은 다음의 태스크들을 동시에 처리한다:
    • 브라우저는 타이머를 설정하고 타이머의 만료를 기다린다. 타이머가 만료되면 콜백함수인 one을 callback queue에 푸시한다. callback queue에 푸시된 one함수는 Stack이 빌때까지 대기하게 된다.
    • two함수가 호출되어 함수 실행 컨텍스트가 생성되고, Stack에 푸시된다. 이후 two함수가 종료되면 Stack에서 팝된다. 이 때 one함수는 아직 callback queue에서 대기중인 상태이다.
  4. 전역 코드 실행이 종료되고 전역 실행 컨텍스트가 Stack에서 팝된다. 이제 Stack에는 아무런 실행 컨텍스트도 존재하지 않게 된다.
  5. 이벤트 루프가 Stack이 비었음을 감지하고, callback queue에서 대기 중인 one을 Stack에 푸시한다. 이후 one실행이 종료되면 Stack에서 팝된다.

사실 자바스크립트 엔진은 Heap과 Stack으로만 구성되어 있고, 단순히 태스크가 요청되면 Stack을 통해 요청된 작업을 순차적으로 실행할 뿐이다.
비동기 처리에서 스스코드의 평가와 실행을 제외한 모든 처리는 자바스크립트 엔진을 구동하는 브라우저 또는 Node.js가 담당한다.

즉, 자바스크립트 엔진은 싱글 쓰레드로 동작하지만 브라우저는 멀티 쓰레드로 동작하는 것!⭐️⭐️⭐️


Job Queue (a.k.a Micro Task Queue)

위 그림에서는 등장하지 않지만 실은 Callback Queue와 비슷한 역할을 하는 "Job Queue"라는 것이 존재한다. HTML스펙에서는 microtask queue라는 이름으로 불리기도 한다.

ES6에서 소개된 Job Queue는 Promise를 사용할 때 콜백 함수 역할을 하는 thenable한 함수들이 추가되는 곳이다.
이 함수들은 Callback Queue가 아닌 Job Queue에 추가되었다가 Event Loop에 의해 Stack으로 옮겨져 실행된다.

📝 사알짝 맛보는 Promise 후속 처리 메서드

  • 프로미스의 처리 결과를 가지고 무엇을 할 것인지를 결정
  • 프로미스 후속 처리 메서드: then, catch, finally
  • 언제나 Promise를 반환한다. = Promise Chaining을 쓸 수 있는 이유!
promiseGet(`${url}/posts/1`)
	.then({ userId } => promiseGet(`${url}/users/${userId}`))
	.then(userInfo => console.log(userInfo))
	.catch(err => console.error(err));

📌 Promise의 후속 처리 메서드(then, catch, finally)의 콜백 함수: Job queue / micro task queue 에 저장.
📌 비동기 함수, 이벤트 핸들러의 콜백함수: Callback queue / task queue 에 저장.

📌 Job Queue 와 Callback Queue의 우선순위: Job Queue > Callback Queue

Job Queue와 Callback Queue의 우선순위는 이곳에서 시각화해 볼 수 있다.


정리

👨: "자, 이벤트 루프에 대해 아는대로 설명해 보세요."

🙋🏻‍♀️: "넵, 동기함수들이 실행 컨텍스트를 생성해서 스택에 푸시되는 반면, 비동기 함수들의 콜백함수들은 callback queue 혹은 job queue로 푸시됩니다.

이벤트 루프는 Stack에 쌓인 동기 함수들이 모두 실행되어 Stack이 비는 때를 기다렸다가, job queue와 callback queue에서 순서대로 콜백함수들을 꺼내어 Stack으로 넣어주는 역할을 합니다.

자바스크립트가 싱글 쓰레드 방식으로 작동함에도 불구하고 이러한 비동기적 처리가 가능한 이유는 이벤트 루프가 브라우저의 구성요소이기 때문입니다. 즉, 자바스크립트 엔진은 싱글 쓰레드 방식으로 작동하지만, 브라우저는 멀티 쓰레드로 작동하기 때문입니다."


Reference

*본 포스팅은 아래 서적/사이트들을 참고 및 인용하여 작성되었습니다.
학습단계로 잘못된 정보가 있을 수 있습니다. 잘못된 부분에 대해 알려주시면 곧바로 정정하도록 하겠습니다 😊

https://medium.com/sjk5766/javascript-%EB%B9%84%EB%8F%99%EA%B8%B0-%ED%95%B5%EC%8B%AC-event-loop-%EC%A0%95%EB%A6%AC-422eb29231a8
https://medium.com/jspoint/how-javascript-works-in-browser-and-node-ab7d0d09ac2f
이웅모, 『모던 자바스크립트 Deep Dive』, 위키북스(2020)

profile
프린이의 코묻은 코드가 쌓이는 공간

0개의 댓글