본문으로 바로가기
해당글은 vincent님의 글인 Javascript 동작원리의 내용을 각색하고 있습니다

자바스크립트는 싱글스레드 구조로 작동되는 언어이다. 메인스레드라고 불리우는 하나의 스레드로 구성되어 있기 때문이다. 싱글스레드는 프로그램이 작동되는 동안 한번에 하나의 작업만을 수행할 수 있다는 뜻이다. 중간에 다른 작업이 끼어들수도 없고, 기존에 진행되던 작업이 종료되어야 그 다음 작업이 수행 가능하다.

 

그런데 자바스크립트의 특징들중 비동기, 동시성, 논블로킹(Non-Blocking)과 같은 싱글스레드와는 상반되는 개념이 등장한다. 분명 한번에 한가지의 작업만을 수행할수밖에 없을텐데, 동시성을 가지는 특성들이 자바스크립트에 내포되어 있는것이다. 오늘은 이러한 동시성이 어떻게 내포되어 있으며, 그 방법이 무엇인지에 대해 글을 써보려고 한다.

자바스크립트의 작동 원리

먼저 자바스크립트가 어떻게 작동되는지부터 알아보도록 하자.

medium.com/@vdongbin/javascript-작동원리-single-thread-event-loop-asynchronous-e47e07b24d1c

위 그림은 자바스크립트의 런타임(자바스크립트 코드가 구동되는 환경으로 Node.js나 웹 브라우저등이 이에 포함됨)의 모습인데 메모리 힙(Memory Heap)과 콜스택(Call Stack)으로 구성되어 있다. 메모리 힙은 메모리 할당을 담당하는 곳이고 콜스택은 코드가 호출될때 스택으로 쌓이는 곳이다. 메인스레드에서 호출되는 함수들은 콜스택에 쌓이게 될것이고 이 함수들은 LIFO(Last In First Out, 후입선출) 방식으로 실행된다. 이 실행 순서또한 이전에 주제삼아 작성했던 글인 호이스팅에 대해 알아보자와 연관이 있다. 그리고 메인스레드와 콜스택을 연관지어 생각해보면 자바스크립트가 싱글스레드 기반의 언어라는 말은 자바스크립트가 하나의 메인스레드와 하나의 콜스택을 가지고 있기 때문이라는 것이다. 이는 아래 예시를 통해 증명할 수 있다.

const fox = () => {
  rabbit();
  console.log('fox');
}
const rabbit = () => {
  console.log('rabbit');
}
fox();
console.log('fox and rabbit');

출력은 아래와 같다

rabbit
fox
fox and rabbit

콜스택의 순서는 아래와 같다

 

  1. fox 함수 실행
  2. fox 함수 내부에서 rabbit 함수 실행
  3. console.log(‘rabbit’) 실행 후 콜스택에서 제거
  4. rabbit 함수 모두 실행되었으니 제거
  5. fox 함수로 돌아와서 console.log(‘fox’) 실행 후 콜스택에서 제거
  6. fox 함수 모두 실행되었으니 제거
  7. console.log(‘fox and rabbit’)가 콜스택에 추가, 실행 후 제거

자바스크립트 런타임과 비동기 

동시성을 가지는 작업들인 비동기, 논블로킹등의 작업들은 자바스크립 엔진을 구동하는 런타임(Runtime) 환경에서 담당한다. 위에서 말했다싶이, 런타임이란 Node.js나 웹 브라우저를 의미한다. 아래 이미지를 보도록 하자.

https://medium.com/@vdongbin/javascript-%EC%9E%91%EB%8F%99%EC%9B%90%EB%A6%AC-single-thread-event-loop-asynchronous-e47e07b24d1c

그림은 자바스크립트 엔진과 런타임 환경이 조합된 모습이다. 그리고 Web API라는 항목을 볼 수 있는데 이는 런타임 환경이 Node.js일 경우 사용할 수 있는 라이브러리와 API를 의미한다.

 

  • 이벤트 루프
    • 이벤트 발생시 호출되는 콜백 함수를 관리하여 테스트 큐에 전달하고, 테스트 큐에 담겨있는 콜백 함들을 콜스택에 넘겨준다
    • 이 작업은 콜스택에 쌓여있는 함수가 없을때에만 수행된다
  • 태스크 큐
    • Web API에서 호출된 비동기 콜백함수들이 기다리는 공간이다. 이벤트 루프가 정해준 순서대로 줄을 서있으며 FIFO 방식을 따른다
  • Web API
    • Node.js 환경에서 자체 지원하는 api로 dom event, ajax, setTimeout등의 비동기 작업들을 수행할 수 있도록 지원한다

런타임 환경에서 비동기 코드가 실행되는 방법

런타임 환경에서 비동기 코드가 실행된다고 가정했을때, 해당 작업은 아래의 순서대로 실행된다.

 

  1. 비동기 작업 코드는 호출스택에 쌓인 후 실행될때 해당 작업을 Web API에 위임한다
  2. Web API는 해당 작업을 수행하고 콜백 함수를 이벤트 루프를 통해 태스크 큐에 넘겨준다
  3. 이벤트 루프는 콜스택에 쌓여있는 함수가 없을경우 태스트 큐에서 대기중이던 콜백 함수를 콜스택으로 넘겨준다
  4. 콜스택에 쌓인 콜백 함수가 실행되고, 해당 작업은 콜스택에서 제거된다

위에서 언급했던 논블로킹의 개념을 이 과정을 통해 설명할 수 있다. 만약 비동기 작업 코드를 동기로 수행했을 경우 해당 함수는 콜스택에 쌓인채로 머물것이고 자바스크립트 엔진은 해당 작업이 끝날때까지(http 요청의 경우 Request URL측에서 대답이 돌아올때까지) 어떠한 작업도 수행할 수 없게된다. 즉, 비동기 작업 코드가 다른 코드를 블로킹 한 것이다. 그러나 비동기 작업을 Web API에 넘겨줌으로써 해당 비동기 작업이 진행될동안 다른 코드들(큐스택에 쌓어야 할 동기 작업들)을 실행할 수 있게된다. 이것이 바로 논블로킹이다.

마치며

자바스크립트 언어는 기본적으로 싱글스레드 언어지만 런타임에 내포된 Web API를 활용하여 멀티쓰레드와 같이 동기와 비동기 작업을 분류하여 진행하는, 멀티쓰레드에서나 가능한 작업을 수행할 수 있게되었다. 중간에 언급된 이벤트 루프의 경우 개별의 글을 하나 더 작성해야 할것으로 생각된다.

'개발 > 프론트엔드' 카테고리의 다른 글

이벤트 버블링  (0) 2021.03.02
화살표 함수의 활용  (0) 2021.02.18
자바스크립트에서의 생성자와 프토토타입  (0) 2021.02.06
클로저(Closure)란?  (0) 2021.01.26
호이스팅(Hoisting)에 대해서 알아보자  (0) 2021.01.18