Node.js


nodejs-light.png
Node, Server-Side JavaScript
홈페이지

1 개요

Node.js는 JavaScript 구현체인 구글 V8에 크로스플랫폼 event 처리 라이브러리인 libuv를 결합한 플랫폼이다.

2 예제 소스

Node.js가 설치된 상태에서 아무 에디터나 띄우고 다음과 같이 코드를 복붙 작성해 보자.

<syntaxhighlight lang="javascript" line="1">
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
</syntaxhighlight>
저장하고 터미널 등에서 'node filename'이라고 입력해주고 나서, 역시 아무 브라우저나 켜고 localhost:1337로 들어가면 아마 'Hello World!'라고 뜰 것이다. [1]

JavaScript에 익숙하지 않고 프로그래밍을 처음 시작하는 입문자의 경우 사실 Hello, World!부터 복잡해보이긴 하다. 때문에 Hello, World! 예제를 조금 풀어서 설명해보자면 다음과 같다.

  • var http = require('http');
Node의 대부분의 기능은 '모듈'이라고 하는 외부 어플리케이션 혹은 라이브러리를 통해 제공된다. 이 코드는 그런 모듈들 중 가장 기본적인 HTTP 모듈을 로드해서 로컬 변수에 할당하는 코드이다. 사실상 별도의 프레임워크를 사용하지 않는다면 대부분 이 코드로 시작하게 된다.
  • http.createServer(function (req, res) {...
createServer 메소드로 새로운 서버를 생성하였으며 이 때 매개변수로 아무런 이름이 없는 익명 함수가 전달된다. 이 익명 함수에 전달되는 두 개의 매개변수는 각각 서버 요청(req)과 서버 응답(res)를 의미한다.
  • res.writeHead(200, {'Content-Type': 'text/plain'});
서버 응답 매개변수에 writeHead라는 메서드를 활용하여 응답 상태와 응답 헤더를 보내고 있다. 응답 해더에는 예제에 나온 Content-Type 외에도 다른 정보들을 포함시킬 수 있다.
  • res.end('Hello World\n');
end 메서드로 통신의 종료를 알린다. end 메서드는 문자열뿐만 아니라 버퍼가 될 수 있는 데이터 청크도 넣을 수 있다. 또한 문자열의 경우 두 번째 매개변수로 문자열의 인코딩을 지정할 수 있다. 기본값은 UTF-8이므로 이외에 인코딩을 써줘야 할 경우에만 입력하면 된다.
  • ...}).listen(1337, '127.0.0.1');
createServer와 이에 매개변수로 전달된 익명함수를 종결하고 listen 메서드로 해당 포트(1337)로 들어오는 연결들을 대기한다. 이 때 listen 메서드는 반드시 생성된 서버 뒤에 붙어야 하며 포트를 명시해줘야 한다. 두 번째 매개변수인 호스트네임(127.0.0.1)은 반드시 제공하지 않아도 되는데, 이 경우엔 http://namu.wiki나 http://localhost와 같은 웹 주소로 연결을 허용한다. 이 listen은 node의 알파이자 오메가라고 할 수 있는 비동기로, http 연결이 맺어지기 전까지 프로그램 실행을 차단하지 않는다.

Hello, World! 예제는 아래와 같이 고쳐서 써도 된다.

<syntaxhighlight lang="javascript" line="1">
var http = require('http');
var server = http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});res.write('Hello, World!\n');res.end();
});

server.listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
</syntaxhighlight>

뭐라고요?

사실 비동기 방식으로 Hello, World를 표시해주는 서버프로그램 같은 개념이므로 초심자들은 겁먹지 말고 인터넷에 널린 node.js 강의들을 하나하나 읽어보도록 하자.

3 비동기

node.js는 고성능의 비동기 애플리케이션 작성 플랫폼으로 구상되었다. 최초 작성자인 Ryan Dahl은 웹 프로그램 분야에서 브라우저의 자바스크립트 엔진이 UI 스레드를 공유할 수 밖에 없는 환경[2]에서 락을 피하고자 시분할과 이벤트로 비동기 프로그램을 작성하는 모습을 보고 괜찮은 방법론이라 생각해 만들었다고 한다.

이때 프로그램은 리엑터 패턴에 의한 CPS(continuation-passing style)로 작성되는데, 이것이 node.js에 고성능을 선사하는 기법인 동시에 비 숙련자에게 디버깅 지옥을 만드는 애증의 관계를 지니고 있다. 궁금하면 위의 간단한 http서버에서 createServer가 인자로 전달받은 함수를 http 요청에 이어지는 실행지정으로 사용한다는 점을 보도록 하자. node.js가 자랑하는 고성능 비동기 프로그램을 작성하기 위해서는 파일시스템을 포함한 프로그램 전체가 비동기화 지점마다 저렇게 CPS로 연결되어야 한다.

이 CPS특징 때문에 Node.js 초심자는 콜백 지옥을 경험하게 된다. 쉽게 설명하자면 코드가 무한들여쓰기로 작성돼서 소스코드가 대각선으로 쓰여지는 현상을 말하는데, 이를 피하려면 익명 함수를 포기하고 아래와 같이 작성하면 된다.


<syntaxhighlight lang="javascript" line="1">
var http = require('http');
var server = http.createServer(helloResponse);

function helloResponse(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});res.end('Hello World\n');
}

server.listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
</syntaxhighlight>

함수를 선언하기 전에 사용하고 있지만 자바스크립트는 함수를 굳이 코드의 위쪽에 선언할 필요 없이 해당 스코프 안에 정의만 돼 있으면 자동 호이스팅이 돼서 사용할 수가 있다. 이게 깔끔하지 않다고 생각해서 콜백 함수를 createServer 하는 위쪽에 선언할 생각을 할 수도 있는데, 이렇게 짜면 피하려고 했던 콜백 지옥에 다시 뛰어드는 꼴이 된다. 콜백이 실행하는 순서가 함수의 자연스러운 실행 순서와 정반대인 아래에서 위로 올라가기 때문이다.

4 npm

npm 사이트

node.js Package Manager. 자바의 Maven, Python의 pip과 같은 node.js용 패키지 관리 및 배포 시스템이다. 본격적으로 node.js를 사용하려면 당연히 필수요소.

5 기타

우리나라에서는 프레임웍으로 표현되기도 하는데[3], node.js는 자바스크립트 엔진에 API를 제공하는 기반 플랫폼(libuv)을 연결한 응용 런타임이라고 보는 것이 더 적당하다. node.js 홈페이지의 설명에도 런타임이라 표기되어 있다. 홈페이지의 About에는 "As an asynchronous event driven framework, Node.js is..."하는 설명이 있는데 이는 node.js가 이벤트 드리븐에 있어 특정하게 지정된 디자인을 제공한다는 의미의 설명이다. 근데 이게 node.js에 이벤트 드리븐 프레임웍을 포함된다는 것이지 이벤트 드리븐 프레임웍 자체가 node.js라는 말은 아니다. 만약 저걸 근거로 node.js가 프레임웍이라고 불려야 한다면 특정 방법론을 구현하는 디자인을 내장한 거의 모든 현대 프로그래밍 언어가 프레임웍이라고 불려야 한다.

비동기 처리로 인하여 I/O 처리시 대단한 성능을 내는 것이 사실이고 기반이 되는 구글 V8도 꽤 빠른 성능을 내는 JIT 구현이지만 개별 프로세스 내부에서 작동하는 자바스크립트 코드는 무조건 싱글 스레드로 실행 한다는 제약이 걸려있어 병렬연산에는 취약하다. 단 node.js에서 싱글 스레드는 성능상의 제약이 아니라 프로그래밍 모델에 포함된 사양이다. 복잡한 비동기 I/O 응용 프로그램을 싱글 스레드 자바스크립트로 짜는 것이 결과물의 실행 속도와 개발 편의성 측면에서 좋다는 것이 node.js의 근간을 이루는 개념이며, 작성자인 Ryan Dahl은 순수하게 연산력이 중요한 요소는 C로 짜서 붙이라는 상식적인 사실을 이야기 했다.

나무위키는 이 node.js와 node.js에서 가장 큰 규모의 웹 프레임워크인 express.js로 개발되어있다.

node.js로 개발하다 보면 모든 것을 비동기 루틴으로 작성해야 하기 때문에, 처음 개발해 보면 소위 말하는 Callback hell이 발생할 수 있다. 이를 해결하기 위해서 Promise pattern이 나왔는데, node.js용 구현체인 node/bluebird, node/Q등을 사용하면 상당히 깔끔하게 프로그래밍 할 수 있다.
2016년 현재 6.0 버전부터 ES6 문법이 대거 추가되면서 ES6 Promise를 사용 가능 하게 되었다.

6 참조

Node.js 공식 참조 문서
Node.js 기본 사용법
생활코딩
Socket.IO - node.js 의 비동기 웹소켓 프레임워크
Express - node.js 웹 어플리케이션 프레임워크
nw.js - node.js 기반으로 웹 애플리케이션을 독립 실행형 앱(데스크톱 응용 프로그램)으로 만들어주는 프레임워크
Electron - nw.js와 같이 node.js와 HTML로 작성된 웹 어플리케이션을 데스크톱 어플리케이션 wrapper로 만들어주는 프레임워크 [4]

나무위키:엔진 [5]
  1. 사실 Node.js 홈페이지에 나와있다.
  2. 브라우저가 DOM API와 자바스크립트 엔진을 동기화 하기 위해서는 어쩔 수 없다.
  3. 사실 해외에서도 조금씩 나오는 이야기다.
  4. nw.js와 비교했을때 가장 큰 차이점은 nw.js의 경우 HTML 페이지를 그대로 어플리케이션 엔트리로 사용하는 반면 Electron은 일반 node 어플리케이션과 동일하게 자바스크립트 파일을 엔트리로 사용한다. 자세한 내용은 Electron이 nw.js와 기술적으로 다른점을 참고하자.
  5. 나무위키는 Node.js의 Express 프레임워크를 이용해 만들어진 사이트이다.