node.js 공부

susu·2022년 4월 29일
0

node.js

목록 보기
1/1
post-thumbnail

들어가기에 앞서

😎 node.js를 선택하게 된 이유

이번 팀 프로젝트에서 백엔드를 맡아 서버 구축에 도전하게 되었다.
스프링은 해본 적이 없고, 그나마 조금 더 익숙한 자바스크립트 기반 프레임워크인 노드를 선택했다.

📕 참고문헌

조현영(2018), <Node.js 교과서>, 길벗

🧐 ?

이 글은 철저히 본인 자습을 위한 기록이므로,
필요에 따라 편안한 문체로 적힐 수 있음을 미리 밝힙니다.

1. 핵심 개념

우선, Node.js는 크롬 V8 자바스크립트 엔진으로 빌드된 자바스크립트 런타임이다.
이 말은 하도 자주 봐서 외웠다
npm은 이 Node.js의 패키지 생태계로서 세계에서 가장 큰 오픈소스 라이브러리 중 하나라고 한다.

꼭 알고 가야할 개념으로는

  • 서버
  • 런타임
  • 이벤트 기반
  • 논블로킹 I/O
  • 싱글 스레드 모델

정도.

1-1. 서버

노드는 서버 애플리케이션을 실행한다.

우리는 클라이언트다.
우리는 서버에게 무언가를 요청하는 주체다.
여기서 우리란 나. 김옥수수. 가 아니다.
정확하게는 나 김옥수수가 사용하는 브라우저, 또는 데스크톱 프로그램, 혹은 모바일 앱 등이 그 주체라고 할 수 있겠다.

서버는 클라이언트의 요청을 응답한다.
웹이나 앱을 사용하여 생성되는 데이터를 어딘가에 저장해 클라이언트로 데려오는 일련의 과정, 즉 response가 서버의 주 역할이다.
(그렇다고 해서 서버가 요청에 응답만 하는 것은 아니다.
다른 서버에 요청을 보내기도 한다.
이때는 요청을 보낸 서버가 클라이언트 역할을 한다.)

즉 서버는 클라이언트의 요청에 응답을 한다.
이 응답은 Yes가 될 수도 있고, No가 될 수도 있다.

여기서 노드가 자바스크립트 애플리케이션이 서버로서 기능하기 위한 도구를 제공하므로 서버의 역할을 한다고 말하는 것이다.

1-2. 런타임

노드 = 자바스크립트 런타임

런타임이란,
특정 언어로 만든 프로그램들을 실행할 수 있는 환경.

즉 노드가 자바스크립트 런타임인 이유는,
노드가 자바스크립트를 컴퓨터에서 실행할 수 있도록 해주기 때문.

노드의 내부 구조

[Node.js Core Library] :
[Node.js Bindings] :
[V8] : JS 엔진, 오픈소스
[libuv] : 라이브러리.
노드의 특성인 이벤트 기반, 논블로킹 I/O를 구현.

1-3. 이벤트 기반?

이벤트가 발생할 때 미리 지정해둔 작업을 수행하는 방식.

여기서 말하는 이벤트란 클릭, 또는 네트워크 요청 등.

이벤트 기반 시스템에서는 특정 이벤트가 발생할 때 무엇을 할 지 미리 등록해놔야 한다.
이걸 이벤트 리스너콜백 함수를 등록한다고 표현한다.

노드는 이벤트 기반 방식으로 동작하므로,
이벤트가 발생하지 않았거나 발생한 이벤트를 다 처리하고 나면 다음 이벤트 발생시까지 대기.

👽 이벤트 루프

여러 이벤트가 동시에 발생했을 때, 어떤 순서로 콜백 함수를 호출할 지를 이벤트 루프가 판단한다.

👽 태스크 큐

이벤트 발생 후 호출되어야 할 콜백 함수들이 기다리는 공간.
콜백들이 이벤트 루프가 정한 순서대로 줄을 서 있으므로, 콜백 큐라고도 부름.

👽 백그라운드

타이머나 I/O 작업 콜백 또는 이벤트 리스너들이 대기하는 곳.

1-4. 논블로킹 I/O

논블로킹이란 이전 작업이 완료될 때까지 멈추지 "않고" 다음 작업을 수행하는 것!

즉, 시간이 오래 걸리는 작업을 기다려주지 않고
'넌 그거 하고 있어라 난 바빠서 먼저 간다..' 하는 것.
참고로 코드를 논블로킹으로 만들어주는 함수 중 하나가 바로 setTimeout(함수, ms) 이다. 전에 바닐라JS 하면서 봤던 함수...!!

cf. 블로킹이란 이전 작업이 완료될 때까지 그 자리를 떠나지 않는 것이다.

function longRunningTask() {
 // 오래 걸리는 작업
  console.log('작업 끝')
 }
 console.log('시작');
 longRunningTast();
 console.log('다음 작업');

이 작업의 실행 결과는
시작
작업 끝
다음 작업
이다.

참고로 동기와 블로킹이 유사하고, 비동기와 논블로킹이 유사한 개념이다.
둘의 관계는 나중에 가서 배우게 된다.

1-5. 싱글 스레드

쉽게 말해, 컴퓨터 작업을 처리할 수 있는 일손을 스레드라고 보면 된다.
멀티 스레드가 싱글 스레드보다 좋아보이지만... 꼭 그런 것만은 아니다.
멀티 스레드는 직원 여러 명을 고용하는 일이므로 비용이 발생하며,
직원이 여러명이 되면 언제나 모든 직원이 일을 하는 게 아니니 노는 직원이 생길 수도 있다는 문제점이 있다.

그렇다면, 예를 들어 한 음식점에 점원이 한명 있다고 치자.
싱글 스레드, 블로킹 모델의 경우 점원 한명이 주문을 받아 주방에 넘기고, 주방에서 나오면 손님한테 서빙을 한 후에 다음 손님의 주문을 받는 구조다.
앞 손님이 음식을 받지 못하면 다음 손님은 주문조차 못한다. 매우 비효율적인 구조임.

이에 반해 싱글 스레드, 논블로킹 모델의 경우 점원이 주문을 받아 주문서만 주방에 넘기고 계속 주문을 받는다. 다음 손님이 기다리지 않아도 되고, 주방에서는 주문을 받은 순서대로 음식을 내놓으니 작업이 효율적이겠지.

2. 서버로서의 node.js

🔼 장점

  • 멀티 스레드에 비해 컴퓨터 자원을 적게 사용
  • I/O 작업이 많은 서버로 적합
  • 멀티 스레드보다 쉬움
  • 웹 서버가 내장되어 있음
  • 자바스크립트를 사용함 (자바스크립트 쉽고 직관적임,, 나도 좋아함,, 짱짱)
  • JSON이 JS 형식이라 데이터 주고받을 때 호환이 쉬움

🔽 단점

  • 싱글 스레드이므로 CPU 코어를 하나만 사용
  • CPU 작업이 많은 서버로는 부적합하다
  • 스레드가 하나니까 하나 있는 스레드가 멈추지 않도록 관리해야 함
  • 서버 규모가 커졌을 때 서버 관리하기 어려움
  • 성능이 좀 어중간..

cf. 서버 외의 노드

React. Angular JS, ELECTRON 등이 노드 기반 프레임워크다.
참고로 슬랙이랑 디스코드가 일렉트론 기반 프로그램이다. 오... 그랬군.

3. ES2015 문법 복기

화살표 함수

const add = (x,y) => {return x+y;};
const add2 = (x,y) => (x+y);

둘이 같은 의미다.
return문을 줄일 수 있다는 점에서 보기 좋게 코드를 적을 수 있다.

이때, 이 화살표 함수가 기존의 function과 가지는 차이점은
this 바인드 방식이라는 것이다.
그럼 this가 뭔데?

this

쉽게 말해, 누가 나를 불렀냐 ?? 다.

const relationship = {
	name: 'zero',
    friends: ['nero', 'hero', 'xero'],
    logFriends() {
    	this.friends.forEach(friend => {
        	console.log(this.name, friend);
        };
    },
};

화살표 개념과 this를 한번에 확인할 수 있었던 예제다.
forEach문에서 화살표 함수를 사용했을 때,
바깥 스코프인 logFriends()의 this를 고대로 물려받는다.
화살표 함수가 this 바인딩 형식을 사용하기 때문이다.

한편 function(friend) 형식으로 함수 선언문을 사용하게 될 경우, friends의 각 요소가 각자 다른 함수의 this를 가지게 되므로 바깥쪽 logFriends의 this를 미리 다른 변수에 저장해놓고 호출해야 한다는 차이점이 있다.

비구조화 할당

그게 뭔데? 싶긴 한데 유용하다고 한다.
객체와 배열로부터 속성이나 요소를 쉽게 꺼낼 수 있는 방법.

const candyMachine = {
	status: {
    	name: 'node',
    	count: 5,
    },
    getCandy() {
	    this.status.count--;
    	return this.status.count;
    }
};

const { getCandy, status: { count } } = candyMachine;

막줄의 이 요상한 코드가 말이 되는 코드라고 한다.
candyMachine 객체 안의 속성을 찾아서 변수와 매칭해주는 것이다.
이게 비구조화 할당이다.
즉, 저 코드의 실행 결과로

const getCandy = candyMachine.getCandy
const count = candyMachine.status.count

를 아주 손쉽게 꺼낼 수 있게 되는 것!
배열도 똑같다.

프로미스

전에 자바스크립트 코드를 볼 때 좀 의아했던(?) 기능.
직관적으로 이해가 안됐는데, 이게 그 유명한 콜백지옥 (콜백 속의 콜백으로 코드가 대각선으로 써지는 현상...) 의 구원자 역할을 한다고 하니 좀 이해가 되는 듯.

프로미스는 다음과 같은 규칙이 몇개 있는데,
우선 프로미스 객체를 생성해야 한다.

const condition = true; // true면 resolve, false면 reject
const promise = new Promise( (resolve, reject) => {
	if (condition) {
    	resolve('성공');
    } else {
    	reject('실패');
    }
});

promise
	.then( (message) => {
    	console.log(message); // 성공(resolve)한 경우 실행
    } )
    .catch( (error) => {
    	console.log(error);
    } );
  • new Promise 문으로 프로미스를 생성할 수 있으며,
  • 안에 resolve와 reject를 매개변수로 갖는 콜백함수를 넣어주었다.
  • 만들어진 promise 변수에 대해 then, catch 메서드를 붙일 수 있다.
  • 프로미스 내부에서 resolve가 실행되면 then이 실행되고,
  • reject가 실행되면 catch가 실행된다.
  • then과 catch는 각각 내부에서 다시 붙여줄 수 있으며, 외부 then의 리턴값을 다음 then으로 넘겨주는 식이다.

즉 then이나 catch가 또다른 promise를 리턴했다면 프로미스가 수행된 후 다음 then이나 catch가 호출되는데,
이를 이용해 콜백 지옥에서 벗어날 수 있는 것.
더이상 함수가 깊어지지 않는다는 의미다.

요정도만 하고.. 일단은 넘어가봅시다

async / await

프로미스로도 여전히 장황한 코드를 다시 한 번 더 깔끔하게 줄여주는 문법이다.

function findAndSaveUser(Users) {
	Users.findOne({}) 
    // findOne({조건}) : 조건에 맞는 객체 한개를 반환, 조건 없으면 인덱스 0번 객체 반환
    // find({조건}) : 조건에 맞는 모든 객체를 반환, 조건 없으면 모든 객체 반환
    	.then( (user) => {
        	user.name = 'zero';
            return user.save();
        } )
        .then( (user) => {
        	return Users.findOne({ gender: 'm' });
        } )
        .then( (user) => {
        	// 생략
        } )
        .catch( (err) => {
        	console.error(err)
        } );
    };

이걸 async와 await를 사용해 줄여봅시다.

async function findAndSaveUser(Users) {
	let user = await Users.findOne({});
    user.name = 'zero';
    user = await user.save();
    user = await Users.findOne({ gender: 'm' });
    // 생략
}

함수 선언부를 그냥 function이 아닌,
async function 으로 대체한 후
프로미스 앞에 await를 붙여주는 방식이다.
await는 해당 프로미스가 resolve 될 때까지 기다린 뒤, user 변수를 초기화하겠다는 뜻.

다만 위의 코드는 에러 처리 부분이 없어서,
try/catch 문과 async/await 문법을 같이 써서 에러를 처리해주어야 한다.

🧐

익숙해져야지... 앞으로의 나 화이팅

profile
블로그 이사했습니다 ✈ https://jennairlines.tistory.com

0개의 댓글