본문 바로가기

nodeJS

NodeJS 기초 , 정의

NodeJs 공부 목표

웹서버를 만들수 있는 사람

데이터베이스를 이해할 수 있는 사람

네트워크를 어느정도 이해되는 사람

 

NodeJS 정의

Node.js는 Chrime V8 Javascript 엔진으로 "자바스크립트 런타임" 입니다.

 

즉 내 컴퓨터(로컬) 자원을 사용 하기 위함이다.

            ↘ 비교를 해보자면 JS 의 Import 의 처리 과정이라 할 수 있다. JS 자체가  파일을 입출력 할 수 있는 능력이 없다. 그래서 컴퓨터를 조작하는 방법중 하나가 Node.js이다. 즉 node.js는 서버만 만들수 있는 아이가 아니다.

 


서버

노드를 통해 다양한 자바스크립트 애플리케이션을 실행할 수 있지만, 노드는 서버 애플리케이션을 실행하는 데 제일 많이 사용합니다.

서버는 네트워크를 통해 클라이언트에 정보나 서비스를 제공하는 컴퓨터 또는 프로그램을 말합니다.

 

웹이나 앱을 사용할 떄는 데이터(아이디, 비밀번호, 이메일 등)와 서비스의데이터가 생성됩니다. 이 데이터를 어딘가에 저장하고, 그 어딘가에서 클라이언트로 데이터를 받아와야 합니다. 이곳이 바로 '서버'입니다

 


이벤트 기반

이벤트 기반(event-driven)이란 이벤트가 발생할 때 미리 지정해둔 작업을 '수행' 하는 방식을 의미합니다.

이벤트로는 클릭이나 네트워크 요청 등이 있을 수 있습니다.

 

이벤트 기반 시스템에서는 특정 이벤트가 발생할 때 무엇을 할지 미리 등록해둬야 합니다.이를 이벤트 리스너(event listener)콜벡(callback) 함수를 등록한다고 표현합니다. 버튼을 클릭할때 경고창을 띄우도록 설정하는 것을 예로 들어보겠습니다. 클릭 이벤트 리스너에  경고창을 띄우는 콜백 함수를 등록해두면 클릭 이벤트가 발생할 때마다 콜백함수가 실행돼 경고창이 뜨는 것입니다.

 

노드는 이벤트 기반 방식으로 동작하므로, 이벤트가 발생하면 이벤트 리스너에 등록해둔 콜백 함수를 호출합니다. 발생한 이벤트가 없거나 발생했던 이벤트를 다 처리하면, 노드는 다음 이벤트가 발생할 때까지 대기합니다.

 

이벤트 이해하기

스트림을 배울 때 on('data', 콜벡) 또는 on('end' 콜백)을 사용했습니다. 바로 data라는 이벤트와 end라는 이벤트가 발생할 때 콜백 함수를 호출하도록 이벤트를 틍혹한 것입니다. creatReadStream 같은 경우는 내부적으로 알아서 dataend 이벤트를 호출하지만, 우리가 직접 이벤트를 만들 수도 있습니다.

 

다음 예제를 통해 이벤트를 만들고 호출하고 삭제해봅시다.

const EventEmitter = require('events')

const myEvent = new EventEmitter();
myEvent.addListener('event1', () => {
  console.log('이벤트1');
  
});
myEvent.on('event2', () => {
  console.log('이벤트2');
})
myEvent.on('event2', () => {
  console.log('이벤트2 추가');
})
myEvent.once('event3', () => {
  console.log('이벤트3');
})
myEvent.emit('event1')
myEvent.emit('event2')
myEvent.emit('event3')
myEvent.emit('event3') // 앞에 실행을 하여 실행이 안됨

myEvent.on('event4',() => {
  console.log('event4');
});
myEvent.removeAllListeners('event4')
myEvent.emit('event4')

const listener = () => {
  console.log('이벤트5');
};
myEvent.on('event5', listener);
myEvent.removeListener('event5', listener)
myEvent.emit('event'); //실행이 안된다.

console.log(myEvent.listenerCount('event2'));

// $ node event
// 이벤트1
// 이벤트2
// 이벤트2 추가
// 이벤트3
// 2

events 모듈을 사용하면 됩니다. myEvent라는 객체를 먼저 만듭니다. 객체는 이벤트 관리를 위한 메서드를 갖고 있습니다.

 

  • on(이벤트명, 콜백): 이벤트 이름과 이벤트 발생 시의 콜백을 연결합니다. 이렇게 연결하는 동작을 이벤트 리스닝이라고 합니다. event2처럼 이벤트 여러 개를 달아줄 수도 있습니다.
  • addListener(이벤트명, 콜백): on 과 기능이 같습니다.
  • emit(이벤트명): 이벤트를 호출하는 메서드입니다. 이벤트 이름을 인수로 넣으면 미리 등록 해뒀던 이벤트 콜백이 실행됩니다.
  • once(이벤트명, 콜백): 한 번만 실행되는 이벤트입니다. myEvent.emit('event3') 을 두 번 연속 호출했지만 콜백이 한 번만 실행됩니다.
  • removeAllListeners(이벤트명): 이벤트에 연결된 모든 이벤트 리스너를 제거합니다.event4가 호출되기전에 리스너를 제거했으므로 event4의 콜백은 호출되지 않습니다.
  • removeListener(이벤트명, 리스너): 이벤트에 연결된 리스너를 하나씩 제거합니다. 리스너를 넣어야 한다는 것을 잊지 마세요. 역시 event5의 콜백도 호출되지 않습니다.
  • off(이벤트명, 콜백): 노드10 버전에서 추가된 메서드로 , removeListener와 기능이 같습니다.
  • listenerCount(이벤트명): 현재 리스너가 몇 개 연결되어 있는지 확인합니다.

이제는 스트림에서 봤던 on('data') 와 on('end')에 대해 알아봤습니다. 겉으로 이 이벤트를 호출하는 코드는 없지만, 내부적으로는 chunk를 전달할 때마다 data 이벤트를 emit 하고 있습니다. 완료되었을 경우에는 end 이벤트를 emit한 것입니다.

 


논블로킹 I/O 

이벤트 루프를 잘 활용하면 오래 걸리는 작업을 효율적으로 처리할 수 있습니다. 작업에는 두가지 종류가 있는데 동시에 실행될 수 있는 작업과 동시에 실행될 수 없는 작업입니다. 기본적으로  자바스크립트 코드는 동시에 실행될 수 없습니다. 하지만 자바스크립트 상에서 돌아가는 것이 아닌 I/O 작업 같은 것은 동시에 처리 될수 있다.

 

I/O 는 입력(input) 출력 (output) 을 의미합니다. 파일 시스템  접근(파일 읽기 및 쓰기 , 폴더 만들기 등)이나 네트워크를 통한 요청 같은 작업이 I/O의 일종이다. 이러한 작업을 할 때 노드는 논블로킹 방식으로 처리하는 방법을 제공합니다. 논블로킹(non-blocking)이란 이전 작업이 완료될 때까지 대기하지 않고 다음 작업을 수행하는 것을 의미합니다. 반대로 블로킹(blocking) 은 이전 작업이 끝나야만 다음 작업을 수행하는 것을 의미합니다.

 

왼쪽 블로킹, 오른쪽 논블로킹

 블로킹 방식보다 논블로킹 방식이 같은 작업을 더 짧은 시간에 처리한다는 것을 알 수 있습니다. 다만, 작업들이 모두 동시에 처리될 수 있는 작업이라는 전제가 있습니다.

노드는 I/O 작업을 백그라운드로 넘겨 동시에 처리하곤 합니다. 따라서 동시에 처리될 수 있는 작업들은 최대한 묶어서 백그라운드로 넘겨야 시간을 절약할 수 있습니다.

 

이렇게 작업 순서에 따라 큰 성능 차이가 납니다. 동시에 처리될 수 있는 I/O 작업이더라도 논블로킹 방식으로 코딩하지않으면 의미가 퇴색되므로 논블로킹 방식으로 코딩하는 습관을 길러야 한다.

 

 


프로세스(Process) 와 싱글 스레드(Single Threads)

 

이벤트 기반, 논블로킹 모델과 더불어 노드를 설명할 때 자주 나오는 용어가 하나 더 있습니다. 바로 싱글 스레드입니다.

싱글 스레드란 스레드가 하나뿐이라는 것을 의미합니다. 작성한 자바스크립트 코드가 동시에 실행될 수 없는 이유이기도 합니다. 스레드를 이해하기 위해서는 프로세스부터 알아야 합니다. 프로세스와 스레드의 차이는 다음과 같습니다.

 

  • 프로세스는 운영체제에서 할당하는 작업의 단위입니다. 노드는 웹 브라우저 같은 프로드램은 개별적인 프로세스입니다. 프로세스 간에는 메모리 등의 자원을 공유 하지 않습니다.
  • 스레드는 프로세스 내에서 실행되는 흐름의 단위입니다, 프로세스는 스레드를 여러 개 생성해 여러 작업을 동시에 처리할 수 있습니다. 스레드들은 부모 프로세스의 자원을 공유합니다. 같은 주소의 메모리에 접근 가능하므로 데이터를 공유할 수 있습니다.

노드가 싱글 스레드라는 말을 들어봤을 것입니다. 하지만 엄밀히 말하면 싱글 스레드로 동작하지는 않습니다. 노드를 실행하면 먼저 프로세스가 하나 생성됩니다. 그리고 그 프로세스에서 스레드들을 생성하는데, 이때 내부적으로 스레드를 여러개 생성합니다. 그중에서 우리가 직접 제어할 숭 있는 스레드는 하나뿐입니다. 그래소 흔히 노드가 싱글 스레드라고 여겨지는 것입니다.

 

 

process

console.log(process);
// 컴퓨터에 대한 정보

console.log(process.version);
// v18.17.1

console.log(process.platform);
// 사용하는 os 알 수 있다. ex. linux

console.log(process.pid); 
//프로세스 id

리눅스 작업 관리자 보기

$ ps -ef

$ ps -ef | grep node

$ sudo kill -x xxxx 프로세스를 끈다. 즉 프로그램을 돌리는 모든것이 프로세스다.

여기서 xxxx 는 프로세스 id 값이다.

 

foreground

 

,background

$ node process.js &

 

 


런타임

브라우저에서는 'window' 이지만 node.js 는'global' 즉 전역객체가 다르다.

 

 


※화살표 함수 

function add1(x, y) {
  return x + y
};

function add2(x, y) {
  return x + y
};

const add3 = (x, y) => x + y;

const add4 = (x, y) => x + y;

function not1(x) {
  return !x;
}

const not2 = x => !x;

add1, add2, add3, add4는 같은 기능을 하는 함수입니다. 마찬가지로 not1, not2도 같은 기능을 합니다. 화살표 함수에서는 function 선언대신 => 기호로 함수를 선언합니다. 또한, 변수에 대입하면 나중에 재사용 할 수 있습니다.

 

화살표 함수에서는 내부에 return 문 밖에 없는 경우, return문을 줄일 수 있습니다. 중괄호 대신 add3add4 처럼 return 할 식을 바로 적으면 됩니다. add4 처럼 보기 좋게 소괄호로 감쌀 수도 있습니다. not2 처럼 매개뱐수가 한 개이면 매개변수를 소괄호로 묶어주지 않아도 됩니다. return문을 줄이는 문법은 자주 사용하므로 눈여겨보길 바랍니다.


node.js 내장객체

  • this
  • 모듈 Module
  • process(process라는 이름을 가진 내장객체가 있다.)
  • os
  • path
  • url, querystring
  • fs(file system)

 

'REPL'

 

자바스립트는 스크립트 언어이므로 미리 컴파일하지 않아도 즉석에서 코드를 실행할 수 있습니다. 브라우저 콘솔 탭에서 자바스크립트 코드를 입력 한 것 처럼 노드도 비슷한 콘솔을 제공하는데, 입력한 코드를 읽고(Read), 해석하고(Eval), 결과물을 반환하고(Print), 종료 할 때까지 반복한다(Loop).

 

  • R: Read 읽는다
  • E: Evaluate 평가한다, 해석한다
  • P: Print 출력한다, 반환한다
  • L: Loop  반복한다.

보통 브라우저의 console 이라고 생각하면 된다.

 


모듈(Modul)

노드는 코드를 '모듈'로 만들 수 있다는 점에서 브라우저의 자바스크립트와는 다릅니다. 모듈이란 특정한 기능을 하는 함수나 변수들의 집합을 말합니다.

모듈로 만들어두면 여러 프로그램에 해당 모듈을 재사용할 수 있습니다. 자바스크립트에서 코드를 재사용하기 위해 함수로 만드는것과 비슷합니다.

보통 파일 하나가 모듈 하나가 되며, 파일별로 코드를 모듈화할 수 있어 관리하기 편합니다.

모듈과 프로그램

 

노드에서는 두 가지 형식의 모듈을 사용하는데, 하나는 CommonJS 모듈이고 다른 하나는 ECMAScript 모듈입니다. 

 


CommonJS 모듈

 

CommonJS 모듈은 표준 자바스크립트 모듈은 아니지만 노드 생태계에서 사장 널리 쓰이는 모듈이다.

// var.js

const odd = 'CJS 홀수입니다.'
const even == 'CJS 짝수입니다.'

module.exports = {
  odd,
  even,
};

var.js에 변수 두 개를 선언했습니다. 그리고 module.exports에 변수들을 담은 객체를 대입했습니다. 이제 파일 모듈로서 기능합니다. 변수들을 모아둔 모듈이 되는 것이죠. 다른 파일에서 이 파일을 불러오면 module.exports에 대입된 값을 사용할 수 있습니다.

// func.js

const { odd, even } = require('./var');

function checkOddOrEven(num) {
  if (num % 2) { //홀수이면
    return odd;
  }
  return even;
}

module.exports = checkOddOrEven;

require 함수 안에 불러올 모듈의 경로를 적습니다. 위 예제에서는 같은 폴더 안에 파일을 만들었지만, 다른 폴더에 있는 파일도 모듈로 사용할 수 있습니다. require 함수의 인수로 제공하는 경로만 잘 지정하면 됩니다. 

 

 

ex) 파일로 실행하기

 

common js

const a = require("./") 가져오기

module.exports = a 내보내기 (JS의 export default a 와 같다)

 

 

nodejs의 this

this === module.exports

브라우저에서의 this와 nodejs의 this는 살짝 다르다. (브라우저에서의 this)

this는 어떤 scope에서 어떻게 사용하냐에 따라 근본이 달라진다.

  1. function에서 사용한다면
    • 함수로써 호출한다면 this는 전역객체(global)을 가리킨다.
    • 메서드로써 호출한다면 this는 메서드를 호출한 객체을 가리킨다.
    • 생성자 함수 호출이라면 this는 인스턴스화 된 객체를 가리킨다.
  2. class에서 사용한다면 this는 인스턴스화 된 객체를 가리킨다.
  3. (⚠️집중!) global scope에서 사용한다면 this는 module.export(module에 있는 exports)를 나타낸다.
// 만약 노드 전역공간이라면
console.log(this === module.exports); // true

// 만약 브라우저 전역공간이라면
console.log(this === window); // true

function test() {
  console.log(this === global);
}

test()
// true

 

 

 

 

 

  

'nodeJS' 카테고리의 다른 글

[Node.js] 예외 처리하기  (0) 2023.09.07
[NodeJS] express  (0) 2023.09.04
[Node.js] Net 모듈  (0) 2023.08.31
[Node.js] 통신(네트워크)  (0) 2023.08.30
[Node.js] 내장 모듈 , require  (0) 2023.08.29