본문 바로가기
  • soldonii's devlog
Javascript 공부/Advanced Javascript(-)

자바스크립트 런타임 : 싱글 쓰레드, 노드 js

by soldonii 2019. 8. 27.

*Udemy의 "Advanced Javascript Concepts" 강의에서 학습한 내용을 정리한 포스팅입니다.

*https://soldonii.github.io에서 2019년 8월 17일(토)에 작성한 글을 티스토리로 옮겨온 포스팅입니다.

*자바스크립트를 배우는 단계라 오류가 있을 수 있습니다. 틀린 내용은 댓글로 말씀해주시면 수정하겠습니다. 감사합니다. :)


1. 싱글 쓰레드(Single Threaded)

 

자바스크립트는 SINGLE THREADED LANGUAGE이다.

자바스크립트의 콜스택은 한 개이기 때문에 다른 작업이 추가로 들어왔을 때, 다른 콜스택에서 작업하는 것이 아니라 현재 콜스택의 위에 쌓이게 되는 것이다. 따라서 자바스크립트는 한 번에 한 개의 작업만을 수행할 수 있다. 비유하자면 내가 현재 음식 a를 먹고 있고, 다음에 음식 b를 먹기 위해 왼손에 쥐고는 있지만 입은 한개니까 a와 b를 동시에 먹을 수는 없고 그렇다고 음식 c를 또 다른 손에 쥐고 있는 것도 불가능한 것과 마찬가지이다. 내가 먹는 행위도 single threaded 한 것이다.

 

그렇기 때문에 자바스크립트는 synchronous한 특성을 가질 수 밖에 없다. 코드가 지시하는 순서대로 한 번에 하나씩만 작업하는 동기적인 언어라서, 언뜻 보기에 속도가 빠를 것 같지 않아 보인다.

 

실제로 자바스크립트의 synchronous한 특성 때문에 문제가 발생한다. 예를 들어 현재 콜스택에서 수행해야 하는 작업이 아주 오랜 시간이 걸리는 작업이라면? 이 작업이 수행되는 동안 사용자는 어떠한 일도 할 수가 없기 때문에 아주 나쁜 user experience를 줄 수 밖에 없다.

다행히도 이를 해결할 방법이 존재하는데, Asynchronous한 방식으로 시간이 오래 걸리는 작업은 브라우저의 백그라운드에서 돌아가도록 처리하고, 당장 빠르게 해결할 수 있는 일을 콜스택에서 수행하는 방식이다. 이러한 작업 수행이 가능한 이유는 자바스크립트가 구동될 때 자바스크립트 엔진 뿐 아니라, 자바스크립트 런타임(Javascript Runtime)이라는 더 큰 범위의 동작 원리가 존재하기 때문이다.

 

2. 자바스크립트 런타임(Javascript Runtime)

자바스크립트 런타임

# Web API

모든 브라우저는 자바스크립트 엔진 뿐 아니라 web API도 함께 제공되는 자바스크립트 런타임을 내장하고 있다. 여기서 web API는 여러가지 기능이 내장된 하나의 애플리케이션이라고 볼 수 있다. web API를 통해 HTTP 요청을 보내거나, DOM 이벤트를 듣거나, 실행을 연기하는 등의 작업이 가능하다.

크롬 브라우저의 콘솔에 window 를 입력하면 브라우저에 내장된 자바스크립트 객체가 나오는데, 이것이 바로 web API이다.(자바스크립트 언어에 내장된 것이 아니라 브라우저에 내장된 것이다.) web API를 이용하여 백그라운드에서 비동기적으로 작업을 처리하고, 해당 작업을 마치면 콜스택에 해당 작업이 끝났음을 알려줘서 그 작업을 수행할 수 있도록 한다.

 

# Event Loop and Callback Queue

콜스택에 web API를 활용한 작업이 들어오면 콜스택은 "이건 내 담당이 아니고 web API가 담당하는 일이네!"라고 인지하여, 해당 작업은 그대로 web API에게 전달한다. 그러면 web API는 해당 작업을 처리하여 콜백 큐(Callback Queue)에게 전달한다.

이벤트 룹(Event Loop)은 끊임없이 콜스택과 콜백 큐를 모니터링하고 있는 존재이다. 만약 콜스택이 비어있을 경우, 콜백 큐에 차곡차곡 쌓여있는 작업들을 콜스택에게 전달하여 최종적으로 해당 작업이 처리되도록 하는 역할이다. 아무리 web API가 빠르게 일을 처리했어도, 만약 콜스택이 비어있지 않으면 이벤트 룹은 콜백 큐의 작업을 콜스택에게 전달하지 않는다.

자바스크립트 런타임에 대한 이해를 통해 single-threaded한 자바스크립트를 Asynchronous하게 이용할 수 있는 힘이 생기게 된다.

 

3. Node.js

자바스크립트 런타임을 통해서 single-threaded한 자바스크립트가 어떻게 비동기적으로 작동해서 속도를 증대시킬 수 있는지에 대해서 배웠다. 하지만 이 모든 것들은 브라우저에 한정된 이야기였다. 즉 클라이언트 사이드 쪽에서만 해당이 되는 이야기인 것이다.

2009년까지만 해도 브라우저에서만 자바스크립트를 쓸 수 있었고, 그래서 꽤 가벼운 언어 취급을 당했었지만, Node.js가 탄생하면서 이야기가 완전히 달라졌다. Node.js는 자바스크립트 런타임 중 하나로, 브라우저 안에서만 놀던 자바스크립트를 브라우저 밖으로 꺼내온 장본인이다.

Node.js 런타임의 구조

 

위 사진이 Node.js의 런타임의 구조이다. 크롬의 V8엔진을 가져왔고, LIBUV를 통해서 비동기적인 작업이 가능하게 구현됐다. 브라우저에 내장된 자바스크립트 런타임과 꽤 유사하게 구성되어 있다. Node.js는 사실 브라우저에서보다 더 많은 일들을 가능하게 한다. 브라우저에서 자바스크립트는 브라우저 외부, 즉 내 컴퓨터에 접근해서 무언가를 수행하지는 못한다. 하지만 Node.js는 내 컴퓨터의 파일 시스템에도 접근할 수 있기 때문에 확장성이 더 넓어진 것이다.

 

참고로 Node.js에는 window 객체는 없다. 이는 브라우저에 내장된 web API이기 때문이다. 대신 Node.js에는 global API가 존재하고, 이 API를 통해서 비동기적으로 작업을 수행할 수 있다. 그렇기 때문에 Node.js가 서버사이드 플랫폼이 된 것이다.

 

전통적인 서버 vs. Node.js 서버 비교

 

Node.js를 서버로 사용하는 것은 PHP 등을 이용한 기존의 전통적 서버 운영방식과 패러다임 자체가 다르다. 기존의 서버는 각각의 HTTP 요청마다 각각의 쓰레드를 생성시켰다. 그래서 만약 아주 많은 요청이 들어올 경우, thread-pool이 꽉차게 되면 먼저 들어온 요청들이 수행될 때까지 다른 작업을 수행할 수가 없었다.

 

반면 Node.js는 single-thread로 구성되어 있으며, HTTP 요청이 들어오면 곧바로 LIBUV 비동기 런타임에게 전달한다. 각각의 방식은 장단점이 있기는 하다. 추후 수업에서 더욱 자세히 다뤄질 예정이다.

댓글