하나는 LTS버전이고 다른 하나는 최신 버전이다. LTS는 Long Term Support 의 약자로 업데이트가 천천히 이루어지는 버전을 이야기한다. 일반 버전과 LTS 버전을 구분하는 기준은 안정성이 기준이다. 새로 나온 제품이 여러 버그를 생성할 가능성이 많듯이 빠르게 업데이트 되는 일반 버전은 안정성이 LTS 버전보다 떨어질 확률이 높다. 그렇기에 상용화 버전에서는 LTS 버전 이용해서 개발한다. 개발하는 환경 자체가 매번 업데이트 되며 진행되면 당연히 좋다. 하지만 긴 기간 동안에 특정 버전에 맞춰서 개발을 진행했는데, 업데이트 된다면, 개발환경의 변화로 인해 다양한 문제가 생길 가능성이 있으므로 LTS 버전을 쓴다. 실제로 위의 14.15.3 LTS 버튼에는 "안정적, 신뢰도 높음"이란 말이 써져 있다.
자신에게 맞는 운영체제를 기준으로 다운로드 받은 다음에 설치하자.
설치가 완료되면 아무일도 일어나지 않는다. Node.js는 윈도우 기준으로 명령 프롬프트를 통해 실행된다. 다른 프로그램으로도 가능하지만 이번에는 CMD로 진행할 예정이다.
윈도우키 + R 키를 누르고 "CMD"를 입력하면 명령 프롬프트가 실행된다.
"node" 를 치고 엔터!
> 이러한 모양이 나올 것이다. 그러면 제대로 설치가 된 것이다.
꺽쇠 모양(">")이 나오는 시점부터는 자바스크립트를 브라우저에서처럼 마음껏 쓸 수 있다.
그렇다면 다른 폴더에 있는 파일을 실행시켜 보자!
먼저,
console.log('HelloWorld');
를 적은 다음에, 원하는 위치에 HelloWolrd.js를 저장하자.
( D:\Pratice\TestHTML\Ch01\HelloWorld.js 에 위치하고 있다.)
설명을 위해서 차례로 입력해보았다.
여기서
$ cd ..
은 상위 폴더로 가기이다. 실제로
C:\Users> cd .. 를 타이핑하고 엔터를 하면
C:\ 로 전환되는 것을 볼 수 있다.
C:\ 에서 D 폴더로 가고 싶으면
C:\ > 에서
$ C:\> D:
D: 를 타이핑하면 된다.
한번에 가려면 C:\Users> cd D:\Pratice\TestHTML\Ch01\를 쳐주자.
JavaScript 런타임은 자바스크립트가 구동되는 환경을 이야기한다. 그러므로 Node.js를 활용해서 자바스크립트를 구동시킬 수 있는 환경을 만들어주는 것이다.]
Node.js가 나오기 전에는 자바스크립트를 구동하려면 웹 브라우저를 통해서 실행시킬 수 밖에 없었는데, Node.js는 이를 극복시켜주었다. 그래서 브라우저의 엔진을 사용하는 것이 아니라 서버에 Node.js를 설치하고 서버 쪽에서 자바스크립트를 구동할 수 있게 만들어 준 것이 Node.js가되는것이다.
그래서 Node.js를 활용한 서버 구동이라는 말이 많이 나오게 되는 것이다.
[한마디로 노드는 서버사이드 자바스크립트로써 많이 사용된다. - Node.js가 백엔드라고 오해하면 안된다. ]
Node.js를 통해 서버를 구현할 수 있을 뿐이다.
* 그래도 Node.js는 확장성 있는 네트워크 애플리케이션을 위해 설계되었으며, 서버를 위해 설계된 플랫폼이다.
* JavaScript를 쓰면 브라우저에 종속적인데, Node.js를 쓰게 되면 컴퓨터 내부에 있는 File System등 System Call도 가능해진다. - 이러한 부분을 Node.js는 libuv를 통해 처리한다.
물론 Node.js가 유일한 서버사이드 자바스크립트는 아니다. 여러 서버사이드 자바스크립트가 존재하며, 요즘 Node.js 가 많이 사용되고 있을 뿐이다.
* 결국 Node.js가 많이 쓰이는 이유는 자바스크립트라는 하나의 언어를 통해 프론트 엔드와 백엔드 둘 다 다룰 수 있게 해주기에 생산성의 향상으로 이어진다. (솔직히, 서버를 위해 추가적인 언어를 사용하기에는 많은 공부와 더불어 인내가 필요하다. 결과를 빨리 보고 싶지만 느려서 짜증이 난다! 이를 해결해준 것은 Node.js이다. 그렇기에 Node.js가 인기를 끌고 있다고 생각한다.)
Node.js의 장점은 그 동작 원리에 의해 나온다.
Node.js는 기본적으로 이벤트 기반 ( Event-Driven ), 논블로킹 I/O( Non - Blocking I/O), 싱글 스레드 라는 특성을 갖는다.
[ 다른 특징적인 장점은 구글 V8 자바스크립트 엔진을 채용해서 빠른 코드 실행과 더불어 단일 스레드와 확장성을 가지며, 버퍼링이 없으며, 데이터를 Chunk로 출력한다. ]
* 빅데이터를 사용하기에는 적합하지 않으며, 많은 데이터 처리용으로는 파이썬의 장고(Django)가 더 적합하다.
블로킹(Blocking), 논블로킹(Non-Blocking) I/O Model
그렇다면 나머지 두 가지는 나중에 알아보도록 하고 논블로킹 I/O에 대해 살펴보도록 하자.
블로킹(Blocking) I/O는 동작하고 있는 동안에는 다른 일을 처리하지 못하는 상태가 된다. 프로그램의 제어권이 호출된 함수가 일을 모두 마무리 될 때까지 넘어가지 않는 것을 이야기한다.
논 블로킹(Non - Blocking) I/O의 경우, 동작을 한 뒤에 바로 다음 제어가 돌아옴으로써 다음 처리로 넘어갈 수 있게 해준다. (앞서 호출된 함수가 일을 마무리 짓지 않아도 다른 함수가 다른 일을 진행할 수 있도록 해주는 것이다.)
* 블로킹과 논 블로킹은 호출된 함수가 언제 return 하는 가에 대한 차이로 나누어 진다.
블로킹 I/O에 비해 논 블로킹 I/O가 일반적으로 효율적으로 사용할 수 있다. 특히, 웹에서 사용되는 자바스크립트의 경우 싱글 스레드를 사용하므로 블로킹으로 진행되게 되면 사용자는 특정 요청을 보내놓은 상태로 무한정 대기해야 한다. (한 마디로 클릭 한번 했다가 홈페이지에서 아무것도 못하는 상태로 기다려야 하는 것이다.)
그래서 이러한 상태를 막기 위해 비동기(Asynchronous) 방식을 채택한다. 백그라운드에서 돌아가야 할 함수는 Web-API를 호출하면서 해결해버린다. (Web-API와 Event-Loop를 활용해서 케어한다.)
동기/비동기, 블럭/논블럭의 차이점은 동기/비동기의 경우 작업의 결과물을 CallBack인 메시지를 통해 주고 받는데, 작업 완료 여부를 신경쓰는지 안 쓰는지에 따라 차이점이 있으며, 블럭/논블럭의 경우 함수 호출이후에 넘어오는 제어권에 따라 블럭이냐 논블럭이냐를 나누는 것이다. 그렇기에
프로그램은 실행하지 않으면 메모리에 탑재(Load)되지 않은 상태로 저장만 되어 있다. 저장된 상태에서 프로그램을 실행하게 되면 메모리에 탑재(Load)되며 이제부터는 프로세스로써 실행되게 된다. 스레드란 프로세스 상에서 하나의 실행 흐름을 이야기한다. 스레드가 1개 일수도 있고 여러개가 될 수도 있다. 각각의 스레드마다 독자적인 스택영역을 가지지만 힙 영역을 공유한다. (한 마디로, 여러개로 작업 처리를 하지만 줄을 서는 대기열은 1줄이라는 소리이다.) 멀티 프로세스의 경우 스택 영역과 힙 영역을 따로 가지는게 일반적이다.
싱글 스레드는 이러한 스레드가 1개인 것을 이야기한다. 1개의 스택 영역과 1개의 힙 영역을 가지는 상태를 의미한다.
그래서 직접적인 다중처리가 불가능하지만 이를 외부 함수 libuv를 통해 비동기적 처리를 넘긴다. 그렇게 싱글스레드이지만 효율적인 처리를 통해 NGINX, 아파치(Apache)와 비슷한 성능을 얻게 되었다. 물론 데이터양이 많이 늘어남에 따라서 기존에 사용하던 서버가 더 좋은 경우도 생길 수 있다. 하지만 간편하게 자바스크립트만 알아도 서버를 만드는 것은 매우 좋은 일이다!
* 근본적으로 자바스크립트는 Block하지 않는 것을 원칙으로 한다. 대부분의 I/O처리는 이벤트와 콜백으로 처리함으로써 콜백을 기다리는 상황에서도 계속 가동될 수 있도록 두는 것이다. (효율적으로 가동한다!)
* 싱글 스레드라곤 하지만 실제로는 몇 개의 스레드가 더 있는 상황이라 봐도 좋다. 내부적으로 싱글스레드일뿐!
(프런트엔드, 백엔드, 하이브리드 애플리케이션, 임베디드 장치 등등 다양하게 서비스된다.)
그렇다면 이렇게 다양하게 쓰이는 자바스크립트가 기본적으로 어떻게 작동되는지에 대해 살펴보고자 한다.
자바스크립트의 여러 엔진 중 하나인 자바스크립트 V8엔진을 통해 알아보도록 하자.
* 이 부분은 어려운 부분이기에 간략하게 읽고 넘어가도 좋다.
너무 어려운 부분을 깊게 파고 들면 자칫 흥미를 잃을 수도 있으므로 아 이러한 구도로 진행되는 군! 정도면 충분하다고 생각한다.
자바스크립트 V8 엔진이란?
V8 자바스크립트 엔진은 구글에서 C++로 작성된 자바스크립트 엔진이다. 구글 크롬(Google Chrome)이 아니더라도 따로 실행이 가능하다. 대표적으로 Node.js가 V8로 빌드되었다. 이러한 V8엔진은 기본적으로 싱글 스레드 (Single-thread)와 콜백 큐(Callback-Queue)가 있다.
크롬은 기본적으로 자바스크립트 엔진 V8을 탑재하고 있다.
자바스크립트 엔진은 구글의 V8엔진 외에도 다른 여러 엔진이 존재한다. 하지만 구글은 더 빠르고 효율적으로 구동하는 엔진을 가지고 싶어했다. 그래서 자바스크립트 코드를 인터프리터를 사용하는 대신 특정 컴파일러를 활용해서 별다른 변형 없이 기계 코드로 변환하는 방식으로 채택하였다. Rhino(Moziila)나 SpiderMonkey 엔진 처럼 JIT(Just in Time) 컴파일러를 구현해서 다이렉트로 기계코드로 변환시키는 것이다. [ V8엔진은 bytecode나 intermediate code를 만들지 않는다. ]
* 사실 자사에 맞는 조금 더 효율적인 자바스크립트 엔진을 갖기 위해서 V8 엔진을 만들었다고 생각한다.
싱글 스레드(Single-thread)?
스레드란 기본적으로 하나의 프로그램에서 프로세스가 실행되는 흐름의 단위를 이야기한다.
그렇다면 프로세스란 무엇인가?
프로세스는 우리가 작업관리자에서도 볼 수 있다. 프로그램은 실행되기를 기다리는 특정한 코드(명령어들)과 데이터들의 묶음이라 볼 수 있다. 이러한 프로그램을 실행하게 되면 코드와 데이터들의 묶음이 메모리에 적재(Load)되면 프로세스가 된다.
프로세스는 일반적으로 실행 중인 프로그램이라 생각할 수 있으며, 실행 중인 무언가라 생각할 수 있다.
반대로 하나의 프로세스는 여러개의 스레드로 구성이 가능하다.
쓰레드는 결국 프로세스에서 하나의 흐름을 이야기한다고 보면 된다. 싱글 스레드는 결국 프로그램에서 하나의 흐름을 갖는다는 이야기이다. (프로세스 내에서 할당 받은 실행의 한 단위라고 생각하면 된다.)
* 스레드는 프로세스 안에서 메모리 공간을 공유하지만, 프로세스는 프로세스 별로 각각의 메모리 공간을 갖는다.
싱글 스레드는 하나의 콜 스택(Call Stack)과 하나의 힙(Heap)을 가진다. 하나의 콜 스택이 있으면 한 번에 하나의 동작만 실행할 수 있다. 하지만 단순히 자바스크립트가 한 번에 하나의 동작만을 실행하고 있다고 생각되진 않는다.
단적인 예로 방 청소를 할 때를 생각해보면 된다. 청소기를 돌리고 있는 상황에서는 청소기 밖에 못 돌리는 것이다. 다른 어떤 일도 처리할 수 없다. 이를 홈페이지에서 적용해보면 된다. 특정 화면이 변하고 있는 상황에서는 아무것도 클릭하지도 조작할 수도 없다. 로딩이 끝날 때까지 기다려야 하는 것이다. 하지만 우리는 클릭도 가능하고, 마우스 스크롤을 통해 홈페이지를 살펴볼 수도 있다.
즉 자바스크립트를 비동기적으로 코드를 실행시킬 수 있게 해주는 것이 Web API, Task Queue, Event Loop가 된다.
자바스크립트 자체는 한번에 하나의 코드만을 실행시킬 수 있지만, 여러 외부 요소가 Web API, Task Queue, Event Loop가 되는 것이다.
기본적인 도식도를 생각해보면 이러한 형태로 이루어져 있다.
( Stack은 컴퓨터에서 사용되는 자료구조의 한 종류로써 블럭을 쌓는 구조라 생각하면 된다. 먼저 넣은 블럭은 차곡차곡 쌓여서 다시 꺼낼때에는 제일 나중에 빼야하는 구조이다. - 자료구조에서 더 자세히 볼 수 있다. )
( Heap은 컴퓨터에서 사용되는 자료구조의 한 종류로써 매점에서 줄을 서는 구조와 비슷하다. 먼저 서서 기다리면 가장 먼저 처리되는 구조이다. - 자료구조에서 더 자세히 보도록 하자.)
Event Loop : Call Stack이 비어잇는지 아닌지 체크를 하고 비어있다면 callback을 Call Stack으로 옮긴다. (그림 상에서 Stack이라 불리는 부분이 Call Stack이다.)
Task Queue : 실행해야할 여러 일을 임시로 대기시키는 큐이다. 일종의 대기열이라고 생각하면 된다.
Web API : Web API는 브라우저 자체에서 지원하는 여러 API들을 의미합니다. 여기서 Web API는 setTimeout, DOM이벤트, Ajax (XMLHttpRequest) 등의 비동기 작업을 수행하도록 API로 지원한다.
* API ( Application Programming Interface) : (응용 프로그램 프로그래밍 인터페이스) 이하 API는 프로그래밍 언어가 제공하는 기능을 제어할 수 있게 만드는 인터페이스를 의미한다.
* 인터페이스(Interface) : 영어 자체를 들여다보면 Inter(사이에, 중간에, 도중에 = between) + face(어떤 것을 바라보다) 란 느낌으로 둘이 서로를 바라보는 것을 의미한다. 그렇다면 interface는 서로가 바라보고 있는 연결면, 접점 등을 의미한다. 하드웨어 인터페이스는 컴퓨터에 있는 랜선과 랜선 연결 커넥터 같은 것들도 하드웨어 인터페이스라 볼 수 있다. 대표적인 인터페이스는 User Interface인 UI가 있으며 이는 컴퓨터와 사람 간의 상호작용에 대한 접점으로 볼 수 있다.
이러한 기본 구조를 통해 자바스크립트가 어떻게 구동되는지 간단하게 옅볼 수 있다.
코드 상에서는 어떻게 작동되는가?
자바스크립트가 비동기적으로 작동하고 있다는 사실은 아래의 코드를 실행해봄으로써 바로 알 수 있다.
1. 콜 스택(Call Stack)에서 first_call_function함수에서 setTimeout 함수가 호출되면 setTimeout은 WebAPI에 의해서 백그라운드에서 실행된다. 이후에 first_call_function함수의 setTimeout함수는 콜 스택(Call Stack)에서 사라진다.
2. first_call_function함수의 setTimeout 함수의 실행이 끝난 뒤에 바로 콜 스택(Call Stack)에서 second_call_function함수의 setTimeout함수가 호출된다. 1과 마찬가지로 setTimeout은 WebAPI에 의해서 백그라운드에서 실행되며, second_call_function함수의 setTimeout함수는 콜 스택(Call Stack)에서 사라진다.
3. WebAPI에서 의해 백그라운드 상에서 정해진 시간이 지난 뒤에 console.log("second_call")이 Task Queue로 옮겨진다. 그리고 그 다음 시간이 지난 후에 console.log("first_call")이 Task Queue로 옮겨진다.
4. 이제 콜 스택(Call Stack)이 비워졌으므로 Task Queue에 있는 console.log("second_call")와 console.log("first_call")가 차례로 실행된다.