WEB 1.0 단반향 통신 위주 -> WEB 2.0 사용자와 상호작용
-> 고성능 JS 필요 -> V8 엔진 등장
-> 고성능 JS 실행 가능 -> JS를 브라우저 외부에서 사용? -> Node.js 탄생
Browser의 JS: 브라우저에서 실행, 웹 내부 제한된 동작, 웹 프론트 개발자의 언어
Node.js: 크로스 플랫폼 실행 가능, 제한 없는 동작, 다양한 어플리케이션 개발 가능
-> React.js(FrontEnd), Express.js(BackEnd), React-Native(MobileApp), Electron(DesktopApp), Brain.js(MAchineLearning)
-> 여러 분야에서 자주 사용된다.
싱글 쓰레드 - 비동기 -이벤트 기반
명령을 실행하는 단위, 한 개의 쓰레드는 한 번에 한 가지 동작만 실행 가능
동작을 실행한 후 완료가 되길 기다리지 않는 방식
동작의 완료를 기다리지 않기 때문에 다른 동작을 바로 실행 가능
Node.js는 싱글 쓰레드이므로 비동기 방식을 사용
비동기 동작의 완료를 처리, 비동기 방식은 특정 동작을 실행한 후, 해당 동작을 전혀 신경 쓰지 않는다.
대신 해당 동작이 완료될 경우 실행할 함수를 미리 등록해 완료 시 다음 함수를 실행한다.
싱글 쓰레드이기 때문에 비동기 동작 필요, 비동기 동작을 구현하기 위해 이벤트 기반
ECMAScript 버전 6 이후를 통틀어 ES6이라 한다.
ECMAScript: 계속해서 발전해나가는 JS의 표준 문법
현대적인 문법으로 생산성 향상, 유용한 문법을 익히고 필요한 부분에 적절하게 활용
Node.js는 ES6의 모든 문법을 지원하지는 않으므로 자주 사용되는 ES6문법을 알아두면 좋다.
let
: 변수
const
: 상수
${value}
: 지정한 변수 불러오기
const arrowFunction = (param) => {}
: 상수형으로 표현 가능, 함수 재선언 불가능
setTimeout((param) => {}, 0)
: 익명함수 간결하게 표현 가능
class Model {constructor(){}getInfo(){}} const model = new Model(,); model.getInfo();
: 일반적인 형태의 class 구현 가능
const obj = {name: 'hi', age: 5}; const {name, age} = obj;
: Object의 key와 같은 이름으로 변수 선언 가능, 다른 이름으로 변수 선언 가능, 순차적으로 변수 선언 가능
비동기: 이벤트 기반 동작을 코드로 구현하는 방법(Callback, Promise, Async-Await)
전통적인 JS의 이벤트 기반 코딩 방식
db.getUsers((err, users) => {
console.log(users);
});
---------------------------------------------------------------------
비동기 동작: db.getUsers 함수는 DB에서 유저 목록을 찾아오는 비동기 동작을 수행
이벤트 등록 / 실행: 쿼리가 완료되면 오류가 있는지, 혹은 유저목록의 결과로 미리 등록된 callback 함수를 실행
callback의 표준: 에러와 결과를 같이 전달하는 것이 표준으로 자리잡혀 있다.
but, 여러 async를 동기적으로 실행해야 할 경우 Node.js는 기본적으로 비동기 동작을 callback으로 처리하기 때문에 계속해서 callback을 사용하는 callback 지옥에 빠지게 된다.
db.getUsersPromise()
.then((users) => {
return promise1(users);
})
.then(something => promise2(something))
.catch(...)
----------------------------------------------------
Promise 함수는 동작이 완료되면 then에 등록된 callback을 실행한다.
오류가 발생한 경우 catch에 등록된 callback을 실행한다.
Chaining, Short-hand 표현 방법으로 더욱 간결하게 코드를 구성할 수 있다.
- Return을 생략할 수 있으며, 인자가 하나인 경우 `( )`를 생략할 수 있다.
function getUsersPromise(params){
return new Promise((resolve, reject) => {
getUsers(params, (err, users) => {
if (err) {
reject(err);
return;
}
resolve(users);
});
});
}
---------------------------------
Promise는 resolve, reject 두 가지 함수를 가진다.
async1 함수의 실행 결과에 따라 resolve, reject로 분리되며,
- reject는 catch에 등록된 callback 실행된다.
- resolve는 then에 등록된 callback 실행된다.
promise의 단점을 보완한 비동기 코딩 방식
async function doSomething() => {
const r1 = await promise1();
const r2 = await promise2(r1);
const r3 = await promise3(r1, r2);
...
return r3;
});
doSomethig().then(r3 => {
console.log(r3)
});
-----------------------------------------------------------
async-await은 promise의 다른 문법
async 함수 내에서 promise 함수의 결과는 await으로 받을 수 있음
await 한 promise 함수가 완료될 때까지 다음 라인으로 넘어가지 않음
순차적 프로그래밍처럼 작성 가능
async 함수의 return은 Promise
function doSomethig(msg){
return promise1()
.then(res => {
console.log(res)
})
.catch(err => {
console.error(err)
});
}
async function doSomethig(msg){
try{
const res = await promise1();
console.log(res);
} catch(err){
console.error(err);
}
}
=> promise 함수와 async 함수는 동일한 동작을 한다.
async function sync(){ // 3초 소요
const r1 = await promise1();
const r2 = await promise2();
console.log(r1, r2);
}
--
async function parallel(){ // 2초 소요
const [r1, r2] = await Promise.all([
promise1(),
promise2(),
]);
console.log(r1, r2);
}
------------------------------------------------------
promise1과 promise2는 각 1초, 2초가 소요되는 비동기 함수
sync 예제에서는 3초의 시간이 소요
parallel 예제에서는 2초의 시간이 소요
Promise.all은 promise 함수를 동시에 실행, 등록된 모든 함수가 마무리되면 결과값을 한꺼번에 반환
callback 지옥 => promise chaining으로 해결
promise 지옥 => async-await으로 해결
현대 js에서는 대부분 가독성이 좋은 async-await을 지향
이벤트를 처리하는 반복되는 동작(loop)
node.js가 비동기-이벤트 동작을 처리하는 일련의 동작
이벤트 루프는 js의 일반적인 동작 방식으로 브라우저에도 존재.
브라우저와 node.js의 이벤트 루프는 기본적인 동작방식에 큰 차이가 없다.
call stack: 작성된 함수들이 등록되는 LIFO 스택
이벤트 루프는 콜스택이 비어있을 때까지 스택의 함수를 실행
=> 콜스택이 비어있을 때까지 스택의 함수를 실행
Message Queue: setTimeout
같은 지연 실행 함수를 등록하는 FIFO 큐
정해진 timing이 끝나고 콜스택이 비어있을 경우 등록된 함수를 콜스택에 추가
=> 콜스택이 비어있을 경우 등록된 함수를 콜스택에 추가
Job Queue: Promise
에 등록된 콜백을 등록하는 FIFO 큐
상위 함수가 종료되기 전에 콜스택이 비어있지 않더라도 잡큐에 등록된 콜백을 콜스택에 추가
=> 콜스택이 비어있을 경우 등록된 함수를 콜스택에 추가
이벤트 루프는 비동기 동작의 실행 타이밍을 이해하는 것이 중요하다.
setTimeout
은 콜스택이 비어있을 때 실행, Promise
는 상위함수가 종료되기 전에 실행
function baz() {
console.log('baz');
}
function bar() {
console.log('bar');
}
function foo() {
console.log('foo');
setTimeout(bar, 0);
baz();
}
foo();
// foo -> baz -> bar
--------------------------------------------------------
setTimeout은 비동기 동작이므로
bar 함수는 메시지 큐에 들어갔다가
foo 함수가 종료되어 콜스택이 비어있을 때 콜스택으로 옮겨진 후 실행