[엘리스sw] 5주차 1일 - Node.js와 MongoDB I
◆ Node.js 이해
◆ Node.js 특징
◆ Node.js 시작하기
◆ ES6
◆ 비동기 코딩
◆ 이벤트 루프
Node.js 이해
Node.js 등장 배경
- 단방향 통신 위주였던 WEB 1.0에서 사용자와 상호작용하는 WEB 2.0으로 발전하게 되면서 웹페이지의 자바스크립트 동작이 복잡해졌고, 이를 실행하기 위해 고성능의 JavaScript 실행기가 필요하게 됨.
- 구글에서는 크롬웹브라우저를 위한 v8이라는 자바스크립트 엔진을 만들게 됨.
Node.js의 탄생
- V8엔진으로 자바스크립트 실행 속도가 굉장히 빨라졌음.
- Node.js는 자바스크립트를 어느 환경에서나 실행할 수 있게 해주는 실행기
Node.js vs Browser
Browser의 JavaScript | node.js |
브라우저에서 실행 | 크로스 플랫폼 실행 |
웹 내부 제한된 동작 | 제한 없는 동작 |
웹 프론트 개발자의 언어 | 다양한 어플리케이션 개발 |
Node.js로 할 수 있는 것들
- Front-End : React.js - 웹서비스
- Back-End : Express.js - 웹서비스
- Mobile-App : React-Native - 한 가지 코드로 iOS와 Android개발
- Desktop-App : Electron - discord, Slack 등 앱 개발
- Machine-Learning : Brain.js - JavaScript로 구현하는 딥러닝
Node.js 특징
싱글 쓰레드 - 비동기 - 이벤트 기반
- 싱글 쓰레드이기 때문에 비동기 동작이 필요함
- 비동기 동작을 구현하기 위해 이벤트 기반 방식을 사용함.
· 쓰레드 : 명령을 실행하는 단위
· 한 개의 쓰레드는 한번에 한 가지 동작만 실행 가능
- 싱글 쓰레드 : 한번에 한 가지 동작만 수행함
- 멀티 쓰레드 : 동시에 여러 동작 수행 가능
싱글 쓰레드의 장점과 단점
- 장점 : 쓰레드가 늘어나지 않기 때문에 리소스 관리에 효율적
- 단점 : 쓰레드 기반의 작업들의 효율이 떨어짐 (ex. CPU 연산 작업)
- Node.js는 비동기 동작으로 쓰레드 기반의 작업을 최소화함.
비동기
- 동작을 실행한 후 완료가 되길 기다리지 않는 방식
- 동작의 완료를 기다리지 않기 때문에 다른 동작을 바로 실행 가능
- Node.js는 싱글 쓰레드이기 때문에 비동기 방식을 사용함
이벤트 기반
- 비동기 동작의 완료를 처리하는 방법
- 비동기 방식은 특정 동작을 실행한 후, 해당 동작을 전혀 신경쓰지 않음.
- 대신 해당 동작이 완료될 경우 실행할 함수를 미리 등록함.
- 비동기 동작이 완료되면 미리 등록된 함수를 실행함.
Node.js 시작하기
어떤 버전으로 시작해야하까?
· Node.js는 빠르게 개발 중
· 보안 이슈 및 버그 수정, 최신기술 빠르게 적용
· 급변하는 기술은 가장 안정적인 최신 버전을 선택하는 것이 최선
LTS | Long-Term Support 버전 Node.js의 안정적이고 오래 지원하는 버전명 |
ES6 | ECMAScript 버전 6 이후를 통틀어 일반적으로 ES6이라고 부름 |
ECMAScript | 계속해서 발전해가는 javaScript의 표준문법 2015년, ECMAScript 버전 6 이후로 많은 현대적인 문법이 추가됨. |
ES6
ES6 사용하는 이유
· 현대적인 문법으로 생산성 향상에 도움이 됨.
· Node.js는 빠르게 최신 ECMAScript를 지원함. ES6의 모든 문법을 지원하지는 않음.
· 자주 사용되는 유용한 문법을 익히고 필요한 부분에 적절하게 활용하는 것이 좋음.
- let, const
- Template String (``, ${})
- arrow function
- class
- destructuring
arrow function
// 상수 함수 선언
const doSomething = () => {
console.log('안녕하세요');
};
// 화살표 문법을 사용하여 간결하게 표현된 익명 함수
setTimeout(() => {
console.log('이름 없는 함수');
}, 0);
// 상수 변수에 새로운 값을 할당하려는 시도 (에러 발생)
// 'const'로 선언된 상수는 재할당할 수 없음
// doSomething = () => {
// console.log('안녕');
// };
class와 destructuring
class Model {
constructor(name, age) {
this.name = name;
this.age = age;
}
displayInfo() {
console.log(`이름: ${this.name}, 나이: ${this.age}`);
}
}
// Model 클래스의 인스턴스 생성
const myModel = new Model('홍길동', 30);
// 객체 속성을 해체하여 추출
const { name, age } = myModel;
console.log(`해체된 이름: ${name}, 해체된 나이: ${age}`);
myModel.displayInfo();
비동기 코딩
· 비동기 : 이벤트 기반 동작을 코드로 구현하는 방법
· Node.js에서 비동기 동작을 구현하는 세 가지 방법을 학습
• Callback : 전통적인 JavaScript의 이벤트 기반 코딩 방식
• Promise : callback의 단점을 보완한 비동기 코딩 방식
• Async-Await : promise의 단점을 보완한 비동기 코딩 방식
Callback
db.getUsers((err, users) => {
console.log(users);
});
- 비동기 동작 : db.getUsers 함수는 데이터베이스에서 유저목록을 찾아오는 비동기 동작을 수행
- 이벤트 등록/실행 : 쿼리가 완료되면 오류가 있는지, 혹은 유저목록의 결과로 미리 등록된 callback 함수를 실행
- callback의 표준 : 에러와 결과를 같이 전달하는 것이 표준으로 자리잡혀 있음.
- 콜백 지옥 우려
Promise
· Promise 함수는 동작이 완료되면 then에 등록된 callback 실행
· 오류가 발생한 경우 catch에 등록된 callback 실행
· Chaining을 사용해 코드를 간결하게 Short-hand 표현 방법으로 더욱 간결하게
- Return 생략 가능
- 인자가 하나인 경우 () 생략 가능
db.getUsersPromise()
.then((users) => {
return promise1(users)
})
.then(r1 => promise2(r1))
.catch();
function doSomething(msg) {
return promise1()
.then(r => {
console.log(r)
})
.catch(e => {
console.error(e)
});
}
callback기반 함수를 Promise 함수로 변경하는 방법
· Promise는 resolve, reject 두 가지 함수를 가짐.
· async1 함수의 실행 결과에 따라 resolve, reject로 분리
- reject : catch에 등록된 callback을 실행
- resolve : then에 등록된 callback을 실행
function getUsersPromise(params) {
return new Promise((resolve, reject) => {
getUsers(params, (err, users) => {
if (err) {
reject(err);
return;
}
resolve(users);
});
});
}
promise의 병렬 실행
· Promise.all : promise 함수를 동시에 실행시키고 등록된 모든 함수가 마무리되면 결과값을 한꺼번에 반환
async function sync() {
const r1 = await promise1();
const r2 = await promise2();
console.log(r1, r2);
}
async function parallel() {
const [r1, r2] = await Promise.all([
promise1(),
promise2(),
]);
console.log(r1, r2);
}
Async - Await
· async-await는 promise의 다른 문법
· async 함수 내에서 promise 함수의 결과는 await로 받을 수 있음.
· await 한 promise 함수가 완료될 때까지 다음 라인으로 넘어가지 않음. → 순차적 프로그래밍처럼 작성 가능
· async 함수의 return 은 Promise
async function doSomething() => {
const r1 = await promise1();
const r2 = await promise2(r1);
const r3 = await promise3(r1, r2);
return r3;
});
doSomething().then(r3 => {
console.log(r3)
});
async function doSomething(msg) {
try {
const r= await promise1();
console.log(r);
} catch(e) {
console.error(e);
}
}
- callback지옥 → promise chaining으로 해결
- promise 지옥 → async-await으로 해결
현대 JavaSript에서는 대부분 가독성이 좋은 async-await를 지향하지만,
특정 상황에 맞는 비동기 코딩 방법들을 구사할 줄 알아야 함.
이벤트 루프
· 이벤트(event)를 처리하는 반복되는 동작(loop)
· Node.js가 비동기-이벤트 동작을 처리하는 일련의 반복 동작
· 브라우저와 Node.js의 이벤트 루프
· 이벤트 루프는 JavaScript의 일반적인 동작 방식으로, 브라우저에도 있음.
· 브라우저와 Node.js의 이벤트 루프는 기본적인 동작방식에 큰 차이가 없음.
· 이벤트루프의 기본적인 동작 원리를 이해하는 것이 중요함.
이벤트 루프 구성요소
Call Stack | 작성된 함수들이 등록되는 LIFO 스택 이벤트 루프는 콜스택이 비어있을 때까지 스택의 함수를 실행 |
Message Queuse | setTimeut과 같은 지연실행 함수를 등록하는 FIFO 큐 정해진 timing이 끝나고, 콜스택이 비어있을 경우 등록된 함수를 콜스택에 추가 |
Job Queuse | Promise에 등록된 콜백을 등록하는 FIFO 큐 상위 함수가 종료되기 전에 콜스택이 비어있지 않더라도 잡큐에 등록된 콜백을 콜스택에 추가 |
· 비동기 동작의 실행 타이밍을 이해하는 것이 중요
· setTimeout은 콜스택이 비어있을 때 실행됨.
· Promise는 상위함수가 종료되기 전에 실행됨.