[생활코딩][WEB2] Node.js

2020. 7. 20. 16:19강의/생활코딩

1. node js

무언가를 배울 때 다른 것보다도 우선 알아볼 것은 역시 그것의 역사와 탄생 배경이다.

원래 자바스크립트라는 것은 html 파일 내에서만 실행될 수 있었다. 당시에 동적인 프로그래밍이 가능한 유일한 언어로 찬양받았지만, 동시에 웹 브라우저에서만 실행이 가능하다는 비난도 함께 받는 상황이었다. 2008년 구글의 크롬이 V8이라는 엔진을 달고 세상에 나왔는데, 이것이 아주 혁명적인 사건이 되었다. V8엔진은 C++로 만들어졌는데 그 간에 어떠한 javascript엔진보다 속도가 빨랐다. 기존에도 웹 브라우저가 아닌 서버 측에서 자바스크립트를 이용할 수는 있었지만 속도의 문제 때문에 널리 사용될 수 없었는데 이것을 해결할 엔진이 오픈소스로 공개된 것이다. 2009년 라이언 달은 commonJs와 V8엔진을 통해 서버 측에서도 빠르게 자바스크립트를 돌릴 수 있는 자바스크립트 런타임인 node.js를 탄생시키게 되고, 이것은 이후 자바스크립트의 발전에 엄청난 영향을 끼치게 된다.

쉽게 말해 node js의 탄생 배경은 자바스크립트를 웹 브라우저가 아닌 다른 곳에서도 사용할 수 있도록 만들기 위함이다.

2. 웹서버

웹 서버가 무엇을 의미하는지는 따로 정리한 적이 있다. (웹서버와 was)

Node.js는 웹서버로서의 기능이 내장되어있기 때문에 apache 같은 웹서버를 따로 사용하지 않아도 된다는 장점이 있다.

var http = require('http');
var fs = require('fs');
var app = http.createServer(function(request,response){
    var url = request.url;
    if(request.url == '/'){
      url = '/index.html';
    }
    if(request.url == '/favicon.ico'){
        response.writeHead(404);
        response.end();
        return;
    }
    response.writeHead(200);
    response.end(fs.readFileSync(__dirname + url));

});
app.listen(3000);

node 명령어를 통해 해당 js파일을 실행시키면 3000번 포트를 통해 접속이 되는 것을 볼 수 있다. 아직 코드 내용을 이해하지는 못했지만, node.js가 웹서버의 역할을 할 수 있다는 것을 확인한 것이다. 이렇게 내장된 기능이 apache와 다른 점은 응답 내용을 프로그래밍적으로 바꿀 수 있다는 것이다. response.end() 안에 내용을 다른 내용으로 바꾸면 localhost:3000을 통해 접속했을 때의 내용이 변하는 것을 볼 수 있다.

3. URL사용

URL은 위와 같은 구조로 이루어져 있다. 여기서 포인트는 query string이다. query string앞에는 물음표를 쓰기로 약속되어 있고, 값과 값은 &로 구분되기로 약속되어 있다. 우리는 query string을 이용하여 웹 서버에 원하는 정보의 구체적인 내용을 보낼 수 있다.

이 URL에 담긴 query string정보를 사용하기 위한 방법을 살펴보자.

기본적으로 이 url은 request.url에 들어있다. 2번에서 사용한 코드를 참고하면 좋다.

한편, url에 담겨있는 사용자가 입력한 정보를 읽기 위해 url모듈을 사용해야 하므로 require('url')을 통해 url모듈을 부르고, 해당 모듈의 parse(). query를 이용하여 정보를 읽어올 수 있다.

var http = require('http');
var fs = require('fs');
var url = require('url');

var app = http.createServer(function(request,response){
    var _url = request.url;
    var queryData = url.parse(_url,true).query;

    if(_url == '/'){
      _url = '/index.html';
    }
    if(_url == '/favicon.ico'){
        response.writeHead(404);
        response.end();
        return;
    }
    response.writeHead(200);
    response.end(fs.readFileSync(__dirname + _url));

});
app.listen(3000);

var queryData = url.parse(_url, true). query는 _url에 담겨있는 query string의 정보들을 객체화하여 리턴해준다.

이러한 원리를 이용하여 동적인 웹페이지를 만들 수 있다. (구체적인 코드는 git에 관리 중이다.)

+ template literal이 html 코드를 인식한다는 것을 알게 되었다.

4. node js로 파일 읽기

node js에서는 파일을 읽기 위해서 File System 모듈을 사용한다. fs라는 키워드로 접근이 가능하다. fs모듈에는 readFile 메서드가 들어있는데, 이것을 통해 특정 파일을 읽어올 수 있다.

세 개의 parameter가 들어가는데 다른 파라미터는 나중에 살펴보고, 맨 첫 번째 파라미터로 읽어오고자 하는 파일명을 적어주면 되는 것이다. 이렇게 파일 읽기 기능과 3번에서의 query string을 이용하는 것을 함께 사용하면, 매우 효과적으로 동적인 페이지를 위한 코드를 작성할 수 있다.

var http = require('http');
var fs = require('fs');
var url = require('url');

var app = http.createServer(function (request, response) {
  var _url = request.url;
  var queryData = url
    .parse(_url, true)
    .query;
  var title = queryData.id;
  if (_url == '/') {
    title='Welcome'; 
  }
  if (_url == '/favicon.ico') {
    response.writeHead(404);
    response.end();
    return;
  }
  response.writeHead(200);

  fs.readFile(`practice/file/data/${queryData.id}`, 'utf8', function (err, description) {
    var template = `
    <!doctype html>
<html>
<head>
  <title>WEB1 - ${title}</title>
  <meta charset="utf-8">
</head>
<body>
  <h1><a href="index.html">WEB</a></h1>
  <ol>
    <li><a href="/?id=HTML">HTML</a></li>
    <li><a href="/?id=CSS">CSS</a></li>
    <li><a href="/?id=JavaScript">JavaScript</a></li>
  </ol>
  <h2>${title}</h2>
  <p>${description}</p>
</body>
</html>
    `;

    response.end(template);
  })

});
app.listen(3000);

주목할 점은 query string 값을 통해 요구하는 값을 받아 온 다음 readFile에 이용하여 본문 내용을 따로 만들어둔 file만 교체하며 페이지를 동적으로 만든다는 점이다!

5. 콘솔 환경에서 입력값 넣기

process.argv의 2번 index부터 node를 실행시킬 때 넣은 입력값이 들어간다. (단, 문자열 타입으로 들어감)

const args = process.argv.slice(2);

console.log(args);

위 코드를 실행시키기 위해 'node ~. js' 입력값; 을 해주면 args에 콘솔을 통해 입력해준 입력값이 들어가는 것을 볼 수 있다.

6. 파일 목록

지금까지의 예제 코드에서는 HTML, CSS, JavaScript 세 개의 파일만 존재하기 때문에 직접 코드를 작성하였지만, 파일이 매우 많아진다면 직접 HTML 코드를 작성하는 데에는 한계가 있을 것이다. 따라서 특정 디렉터리에 있는 파일들을 배열 형태로 담아주는 file system모듈의 readdir 메서드를 통해 파일들을 읽어오고, 반복문을 통해 이 정보들을 관리할 수 있다.

7. 동기와 비동기

동기와 비동기는 이 사진 하나로 설명이 된다. 동기적이라는 것은 말 그대로 직렬적으로 처리를 하는 것이고 비동기적이라는 것은 병렬적으로 처리가 가능함을 의미한다. 두 번째 작업이 아주 오래 걸리는 작업이고, 내가 직접 하지 않아도 된다고 생각한다면 비동기적으로 실행하는 게 아주 합당하다. 자바스크립트는 비동기적인 동작이 가능한 언어이다. 비동기적인 것은 매우 효과적이지만 동시에 매우 복잡하다. nodejs를 통해 코딩을 하는 것이 상당히 헷갈리는 이유도, 비동기적 처리를 위한 복잡한 작업 때문일 것이다.

var fs = require('fs');

/*
//readFileSync
console.log('A');
var result = fs.readFileSync('syntax/sample.txt', 'utf8');
console.log(result);
console.log('C');
*/


console.log('A');
fs.readFile('syntax/sample.txt', 'utf8', function(err, result){
    console.log(result);
});
console.log('C');

코드를 통해 결과를 예측해보자. readFileSync의 경우 A, B, C가 순서대로 출력되는 것을 볼 수 있다.

반면에, readFile은 세 번째 인자로 콜백 함수가 들어온다. 콜백 함수의 개념이 매우 헷갈리는데, 우선 이해한 바로는 인자 값으로 함수를 넘겨주어, 넘겨받은 쪽에서 그 함수를 호출하면 그때서야 실행이 되는 것이다. 여기서 말하자면 console.log('A')를 호출한 후, readFile을 통해 콜백 함수를 넘겨주고, 바로 console.log('C')를 호출한 후, 콜백 함수가 넘겨받은 쪽에서 실행이 된 결과, 즉 console.log(result)가 실행된다.

콜백 함수는 쉽게 말해, 인자로 넘겨주는 함수인데 비동기적인 코드에 이용하면 병렬적인 작업을 처리할 수 있게 된다.

8. Package Manager

패키지를 독립적으로 실행되는 하나의 프로그램이라고 생각해보자. 프로젝트를 진행할 때는 수많은 패키지들이 사용되는데, 이러한 패키지들을 생성하고 설치하고 삭제하고 업데이트하는 등의 작업을 해주는 것을 패키지 매니저라고 한다. node js에서 가장 광범위하게 사용되는 패키지 매니저는 ' NPM '이다. 이 npm을 통해 프로세스를 관리해주는 pm2라는 프로그램을 설치해보자. (pm2는 원치 않은 프로그램이 종료 시에, 자동으로 다시 켜주는 작업이나, 코드 수정 시 자동으로 업데이트하여 재실행해주는 등의 프로세스 관리를 해주는 프로그램이다.)

npm install pm2 -g

이때 -g의 의미는 해당 프로그램이 독립된 소프트웨어이기 때문에, 어느 곳에서든 사용될 수 있도록 설치되어야 한다는 의미이다.(global 하게) 이후 pm2 start main.js 등의 명령을 통해 pm2를 사용할 수 있다. (다양한 기능이 있으므로 홈페이지를 참고하여 사용해보면 재미있다. 가장 유용했던 건 수정 시에 알아서 껐다 켰다 해주는 pm2 start main.js --watch)

9. CRUD

코드

노드를 통해 사용자로 하여금 CRUD기능을 할 수 있도록 만드는 코드를 작성하였다. 각각에 대한 설명은 너무 방대하여서 따로 정리하지 않고 집중하여 강의를 들은 것 같다. key point는 file system 모듈을 이용하여 검색을 하면 쉽게 방법이 나온다는 것이다. 이 모듈의 메서드들을 통해 CRUD를 구현하는 연습을 꾸준히 해서 안 보고도 구현할 수 있도록 해야겠다. 

 

+ node용 branch를 따로 파서 코드를 진행하였는데 잔디가 안 심어졌다... 알아보니 default branch가 아니면 잔디가 안 심어지는 것이었다. 다만, 이것을 master branch로 merge 할 경우 해당 commit 날짜로 잔디가 심어지니까 안심할 일이다 ~

 

10. 객체

 

객체는 정보를 정리 정돈한다는 점에서 배열과 닮았다. 하지만, 배열이 정보에 순서가 정해져 있다면 객체는 그렇지 않다. 정보에 접근하기 위해서 배열이 index를 이용한다면 객체는 정보의 이름을 이용할 수 있다.

const arr = ['kim','min','seob'];

console.log(arr[1]);

const obj = {
	first : 'kim',
	second : 'min',
	third : 'seob'
}

console.log(obj.second);

두 결과 모두  min을 출력하는 것을 볼 수 있다.

 

객체의 정보들을 반복문을 통하여 조회하고 싶다면 약속된 키워드  for... in 을 사용해야 한다.

for (var target in obj) {
	console.log(target + ' ' + obj[target]); // first kim second min third seob
}

위와 같이 obj객체 안의 key값을 target값에 넣는 방식으로 반복 조회를 하는 것을 볼 수 있다. 

또는 전체 구조를 보고 싶다면 아래와 같이 하여 결과를 확인할 수도 있다. 

console.log(Object.entries(obj));

 

객체에는 함수도 정보로써 들어갈 수가 있는데, 공통된 대상을 조작하는 여러 함수는 하나의 객체에 넣어 보관함으로써 그 역할을 좀 더 분명히 할 수 있다. 또한, 함수가 매우 많아질 경우 공통된 함수 이름을 사용하는 실수가 발생하기 쉬운데, 이럴 때일수록 객체에 함수를 넣어 사용해주면 중복된 함수 이름으로 인해 코드가 꼬이는 일을 방지할 수 있다. 

 

 

'강의 > 생활코딩' 카테고리의 다른 글

[생활코딩][WEB3] Express  (0) 2020.08.30
[생활코딩][WEB3] Ajax  (0) 2020.07.13
[생활코딩][WEB2] JavaScript  (0) 2020.07.08
[생활코딩][WEB2] CSS  (0) 2020.06.26
[생활코딩][WEB1] HTML & Internet  (0) 2020.06.24