[엘리스 sw 엔지니어 트랙] 21일차 ES6, Node.js, CommonJS

오경찬·2022년 5월 12일
0

수업 21일차

이제는 Javascript를 끝내고 Node.js으로 들어서는 입문의 길이다. 벌써...? 나는 아직 할줄아는게 없는데...? 생각이 드는 날이다 ㅜㅜ

이론

ES6

우선 ES란, ECMAScript 의 약자이며 자바스크립트의 표준, 규격을 나타내는 용어이다.
뒤에 숫자는 버전을 뜻하고 ES5는 2009년 ES6는 2015년에 출시되었다.
오늘은 ES6에 추가된 기능들을 알아볼 것이다.

let, const 키워드 추가

기존의 var키워드에 비해 블록 레벨 스코프를 가지며 재할당이 가능한 let, const 키워드가 추가되었다.
변수의 생명주기에 영향을 끼치며, 키워드만 보아도 변수의 변화가 생기는지 안생기는지를 알 수 있게 되었다.

화살표함수

화살표 함수가 추가되어 함수를 간결하게 나타낼 수 있게 됐다.
가독성 및 유지 보수성이 올라갔다고들 한다.

화살표 함수에서는 매개변수가 하나일 때 () 생략 가능, {} 및 return 도 생략이 가능하다.

// ES5
function foo(a, b) { 
  return a + b;
}

// ES6
const foo = (a, b) => a + b;

Default Parameter 추가

기존에는 함수의 매개변수에 초기화를 하려면 내부 작업이 필요했으나, ES6 에서는 필요 없어졌다.

function foo(a, b) {
	var a = a || 10;
  	var b = b || 20;
  
	return a + b;
}
console.log(foo(50, 50))	// 100

const foo = (a = 10, b = 20) => a + b;
console.log(foo());	// 30

Templete literal

ES6이전의 문자열 관리는 불편했으나, Templete literal 이 생기고 나서 편해졌다.

사용법은 ``(back tick)으로 가능하다.
${} 중괄호 앞에 달러 표시를 통해 자바스크립트 표현식 사용이 가능하다.

// ES5
var str1 = ', ';
var str2 = 'World!';
var str3 = 'Hello' + str1 + str2;

// ES6
let str1 = ', ';
let str2 = 'World!';
let str3 = `Hello ${str1} ${str2}`;

Multi-line String

문자열이 라인을 넘어가게 되면 '\n' 과 덧셈 연산자를 사용했어야했다.
백 틱을 사용하게 되면서 여러줄의 문자열 관리도 편해졌다.

// ES5
var str = 'asdasdsadsadsadsadsadzxcxzcxzdasdsa.\n' + 
'qwewqewqeqwewqeqwewqewqeqweqweq.\n'

// ES6
let str = `asdasdsadsadsadsadsadsadsadsadasdasdsadasdsad
zxcxzcxzczxczxcxzczxcxzczxzc`;

클래스

객체 생성 방식 중 하나이며, 자바스크립트는 프로토타입 기반의 객체 지향 언어이다.
클래스 기반의 객체 지향 프로그래밍에 익숙한 개발자들의 요청에 의해 생긴 것 같다.
자바스크립트에서 클래스는 객체를 생성하는 함수라고 생각한다.

단, 생성자 함수와 동일하게 작동하지는 않으며, 클래스가 더 엄격하여 호이스팅이 발생하지 않는 것 처럼 let, const 키워드처럼 동작하게 된다.

모듈

모듈이란, 재사용하기 위한 코드 조각을 뜻하며, 세부사항은 캡슐화 시키고, API 부분만 외부에 노출시킨 코드이다.

<script type="module" src="lib.mjs"></script>

type에 module을 추가시키고 확장자를 mjs로 변경하여 사용한다.
모듈은 모듈 스코프를 가지며, import와 export 키워드를 이용하여 사용한다.

구조분해 할당

구조분해 할당이란 객체나 배열에서 사용하며 개별 변수에 값을 할당하는 방식이다.

const arr = [1, 2, 3];
const [one, two, three] = arr;

one // 1
two // 2
three // 3

const obj = {
 firstName: "Jeon",
 lastName: "JiHo"
};

const { firstName, lastName } = obj;
firstName // "Jeon"
lastName // "JiHo"

배열은 순서를 중요하게 여겨 순서가 바뀌면 값도 바뀐다, 객체는 키를 중요하게 여겨 순서 상관없이 키를 따라가게 된다.

Promise

비동기통신에 있어 기존에는 콜백 함수를 사용한, 콜백 패턴을 사용하였다. 결과론적으로, 콜백헬을 발생시켰다.
이를 해결하기 위해 프로미스가 도입되었고, 프로미스 후속처리 메소드를 이용해 에러 처리를 효과적으로 할 수 있게 되었다.

String 메소드(includes, startsWith, endsWith)

const str = 'Hello World Jeon JiHo";
str.includes("Jeon");		// true
str.startsWith("Hello");	// true
str.endsWith("JiHo");		// true

포함되어있는지(includes), 시작하는지(startsWith), 끝나는지(endsWith)
boolean 타입을 return 해준다.

Node.js

Node.js(이하 노드)는 Chrome V8 자바스크립트 엔진으로 빌드된 자바스크립트 런타임입니다. 종종 어떤 사람들은 프레임워크라고 보기도 하지만 공식문서에서는 런타임이라고 이야기 합니다.

런타임(runtime)이란 특정 언어로 짜여진 프로그램들을 실행할 수 있는 환경을 의미합니다. 자바스크립트 런타임 이라는 것은 자바스크립트로 짜여진 프로그램을 실행할 수 있는 환경이라는 의미가 됩니다.

노드는 런타임이기때문에 자바스크립트 프로그램을 실행할 수도 있고, 단순히 서버를 실행시켜버릴 수도 있습니다. 또는 우리가 익히 알고있는 웹 프레임워크도 노드를 기반으로 돌아가기도 합니다. 서버도 간단히 이야기 하고 넘어가자면 서버는 네트워크 통신으로 클라이언트에 서비스를 제공하는 것을 의미합니다. 서버는 컴퓨터가 될 수도 있고 프로그램이 될 수도 있습니다. 동작은 클라이언트가 요청을 하면 서버가 응답을 하는 식으로 동작합니다.

노드가 빠르고 강력하게 동작하도록 해주는 원리는 노드의 내부구조에 들어있습니다. 노드가 V8 자바스크립트 엔진을 이용한다고 했는데 그외에도 libuv, llhttp 등의 라이브러리를 참조하고 있습니다. 각 참조 라이브러리와 도구에 대해서는 참조 링크의 의존성 항목에 자세히 나와있습니다.

그럼 노드가 뭔지 소개를 했으니 노드의 특성들을 알아보겠습니다.

Node.js의 특성

이벤트 기반 동작 Event driven

이벤트 기반 동작은 이벤트 발생 시 해당 이벤트에 미리 설정한 작업을 수행하는 작업 방식입니다. 이벤트는 웹 브라우저 상에서 일어나는 모든 일들을 의미합니다. 클릭, 드래그, 키다운, 새로고침 등 페이지 상에서 할 수 있는 모든 행동들이 이벤트가 됩니다.

이벤트 기반 동작을 하기 때문에 프로그래머는 이벤트에 따른 작업을 미리 지정해놔야 합니다. 이때 이벤트 리스너에 함수를 등록하게 되는데 이 함수를 콜백 함수라고 합니다. 이렇게 지정을 했다면 사용자가 브라우저 상에서 특정 이벤트를 발생시키면, 해당 이벤트에 등록되어있는 콜백 함수가 실행됨으로써 이벤트에 대한 작업을 수행하게 되고, 이것을 이벤트 기반 동작이라고 합니다. 이 과정들을 정리해보면 다음과 같습니다.

  1. 프로그래머가 이벤트 리스너에 콜백 함수를 등록한다.
  2. 클라이언트로 부터 이벤트가 발생한다.
  3. 이벤트에 등록된 콜백함수를 호출해서 작업을 실행한다.

이벤트 루프 Event Loop

노드에서 이런 이벤트들을 관리하고 실행하기 위해 이벤트 루프(Event Loop)개념을 이용합니다. 이벤트 루프는 한 번에 여러개의 이벤트가 발생했을 때 이벤트에 대한 콜백 함수 호출 순서를 판단하는 역할을 합니다. 이는 노드의 시작부터 종료까지 이벤트 처리를 위해 동작을 계속해서 반복하기에 루프라는 이름이 붙게 되었습니다.

한가지 예시로 이벤트 루프와 일련의 동작들에 대해서 소개를 해보겠습니다. 아래의 코드를 Call Stack으로 나타내보면 다음과 같습니다.

function a() {
  b();
  console.log('a');
};

function b() {
  console.log('b');
};

a();


하지만 이상태에서 setTimeout과 같은 비동기코드가 들어오면 어떻게 할까요? 기다렸다가 실행하게 될까요? 호출스택만으로는 모든 것을 설명하기 어렵습니다. 그래서 우리는 이벤트 큐와 호출 스택 그리고 백그라운드를 이용해서 설명을 하게 됩니다.

  1. 콜백이 들어오면 Call Stack에 push한 다음 실행할 차례가 되면 스택에서 pop합니다. 그리고
  2. 그 안에 담긴 내용을 백그라운드에서 수행시킵니다.
  3. 수행된 작업은 태스크 큐로 enQueue됩니다.
  4. 이벤트 루프가 콜스택이 비었는지 아닌지 확인하고, 비었다면 태스크 큐의 작업을 콜스택으로 보내고 그렇지 않으면 대기시키는 역할을 하게 됩니다.

이것이 이벤트 루프와 그 일련의 동작과정들 입니다. 그래서 setTimeout()같은 경우 실행해보고 실제로 초를 시간을 측정해본다면 지정한 시간에 맞출 수도 있고, 그보다 느릴 수도 있는 경우가 발생합니다.

논 블로킹 입출력 모델

입출력은 정보를 입력하고 보내는 것 들을 통칭합니다. 파일 시스템이나 네트워크 요청 등도 모두 입출력이라고 할 수 있습니다. 그리고 노드에서 입출력 작업은 다른 작업과 동시에 실행이 될 수 있습니다. 그래서 우리는 노드의 이런 동작을 논 블로킹 입출력 모델이라고 부릅니다.

블로킹과 논 블로킹을 설명하자면, 블로킹 모델은 한 작업이 시작되면 그 작업이 끝날 때 까지 다른 요청은 작업을 수행하지 못하고 기다려야하는 방식입니다. 논 블로킹은 이전 작업의 끝을 기다릴 필요없이 요청이 오는대로 수행을 시작하는 것을 의미합니다. 당연히 우리는 논 블로킹 모델을 이용하는 것이 빠르게 작업을 수행할 수 있음을 알 수 있습니다.

노드는 논 블로킹 입출력 모델을 채택했기 때문에 코드를 작성할 때 논 블로킹 방식을 최대한 활용하게끔 만들어주어야합니다. (채택을 했을 뿐 컴퓨터는 명령을 내리지 않으면 당연히 모릅니다.) 그래서 이때 자주 이용하게 되는 기술이 setTimeout(콜백, 0), setImmediate(콜백) 등과 같은 내장 객체들을 이용해서 논 블로킹을 활용하도록 합니다.

제어가능한 스레드는 하나

우선 스레드란 프로세스 내부에서 실행되는 흐름의 단위입니다. 프로세스는 OS로 부터 받는 작업의 단위입니다. 더 쉽게 이야기하자면, 프로세스가 하나의 일이면 스레드는 그 일에 할당된 일꾼들이라고 이해하도록 합시다.

프로세스는 스레드를 여러개 만들 수 있기에 하나의 작업을 받으면 여러 스레드가 일을 처리하도록 합니다. 노드는 하나의 프로세스를 만들고 그 밑에 여러 개의 스레드를 생성합니다. 우리가 이 스레드들을 모두 관리하면 좋겠지만 아쉽게도 노드에서는 하나의 스레드만 직접 제어가 가능합니다. 그렇기 때문에 노드가 싱글 스레드 같다라는 표현을 어디선가 종종 볼 수 있는 것입니다. 노드를 이용할 때는 여러개의 프로세스를 만드는 방식으로 이용하게 됩니다.

CommonJS

자바스크립트를 서버사이드및 데스크탑 어플리케이션에서지원하기 위해서 만들어졌다. 다른 모듈을 사용할 때에는 require을,모듈을 해당 스코프 밖을로 보낼 때에는 module.exports를 사용하는 방식으로, Node.js에서는 이방식을 사용하고 있다.

const printHelloWorld = () => {
  console.log('Hello Wolrd');
};

module.exports = {
  printHelloWorld
};
profile
코린이 입니당 :)

0개의 댓글