본문 바로가기
코딩/군 장병 AI·SW 역량강화 교육

[군 장병 AI/SW 교육] Node.js 이해하기 2 / Express.js 기초 1

by 나는준이 2023. 11. 18.
반응형

 

군 장병 AI/SW 교육 / 엘리스 코딩/ [초급] 웹 개발 프로젝트 / Express.js 기초 1 / Node.js 이해하기의 노트필기입니다

-- Node.js 이해하기 2 --

목차

 
1. ES6 

2. 비동기 코딩 <==

    가. 비동기 코딩

    나. Callback

    다. Promise

    라. Async - Await


가. 비동기 코딩

1) 비동기 코딩

비동기 : 이벤트 기반 동작을 코드로 구현하는 방법

-어떤 일을 시킬때 그 일의 끝을 기다리지 않고 다른 일을 진행하는것이다.

 

2) Node.js의 비동기 동작을 구현하는 방법 

가) Callback

전통적인 JavaScript의 이벤트 기반 코딩 방식이다.

나) Promise

Callback의 단점을 보완한 비동기 코딩 방식

다) Anync - Await

Promise의 단점을 보완한 비동기 코딩 방식

 

나. Callback

1) Callback

먼저 아래 예시에서 db.getUsers라는 함수가 있고, 이 함수 안에 익명함수가 있는 것을 확인 할 수 있다. 이때 밖에 있는 db.getUsers라는 함수는 데이터베이스에서 유저 목록을 찾아오는 비동기 동작을 수행한다. 즉, 이 동작은 Node.js가 하는 일이 아니라, 일을 시키기만 하고 결과가 오면 console.log라는 함수를 실행시키는 코드인 것이다.

쿼리가 완료되면(db.getUsers가 끝나게 되면) 오류나 결과를 바탕으로 미리 등록된 callback 함수를 실행한다.

 

*callback의 표준

에러와 결과를 같이 전달한다. 아래 예시에서는 첫번째 인자 err로 에러를, 두번째 인자 users로 결과를 전달한다. 이렇게 에러와 결과를 같이 전달함으로서 callback함수에서 다루기 쉽게 한다.

db.getUsers((err, users) => {
	console.log(users);
    });

 

 

2) Callback 지옥

Callback 방법에는 한가지 단점이 있다. 콜백함수를 여러번(중첩적으로) 사용하게 되면 코드의 가독성이 나빠지고 복잡해진다는 것이다. 이를 콜백 지옥이라고 부른다. 아래는 콜백지옥에 빠진 코드 예시이다.

db.getUsers((err, users) => {
	if (err) {
    ...
    return;
    }
    async1(users, (r1) => {
    	async(r1, (r2) => {
        	async(r2, (r3) => {
            	...
            });
        });
    });
});

 

다. Promise

1) Promise의 등장

Callback의 콜백지옥 문제를 해결하기 위해 promise 함수가 등장했다.

Promise 함수는 동작이 완료되면 then에 등록된 callback을 실행한다. 오류가 발생한 경우 catch에 등록된 callback을 실행한다.

 

2) 장점

Promise 방법은 어떤 한 함수에 다른 함수가 들어간 형태가 아니라 여러 일들이 연쇄적으로 일어나는 형태이다. 따라서 가독성이 더 좋고 사용하기 편리하다는 장점이 있다. Chaining을 사용해 코드를 간결하게, Short-hand 표현 방법으로 더 간결하게 할 수 있는 것이다. 또한 return을 생략 가능하며 아래 예시 5번째 줄에서 볼 수 있듯이 인자가 하나인 경우 ()를 생략할 수 있다.

db.getUsersPromise()
    .then((users) => {
    return promise1(users);
   })
   .then(r1 => promise2(r1))
   .catch(...);

 

3) Promise 지옥

이런 promise도 then이 꼬리에 꼬리를 물고 등장한다면 결국엔 callback과 비슷한 문제점이 나타나게 된다. 이 상황을 어떻게 해결 할 수 있을까? 직관적으로 생각한다면 콜백 지옥을 해결한 방법과 유사한 방법을 사용하면 해결될 것 같다. 그리고 그것이 async -await이다.

 

다. Async - Await

1) Async - Await의 등장

Async - await은 어떤 작업을 함에 있어서 이 작업을 하겠다, 이 작업을 받겠다라는 것을 명시하는 구문이다. Aysnc - await은 기본적으로 promise의 다른 문법이다. Aysnc라는 것이 동작하게 되면 그 안에서 await을 동작 할 수 있다. 그리고 Await이 끝나기 전까지는 다음으로 넘어가지 않는다.

Aysnc 안의 await들이 끝나면 다음 코드로 동작을 하는데 중요한 것은 await 간에는 작업을 비동기로 진행할 수 있다는 점이다. 따라서 작업을 하나 씩 하는 것 보다는 시간을 단축할 수 있다. 그래서 마치 순차적 프로그래밍처럼 작성 가능하다.

Async 함수의 return은 Promise다. 즉, 뒤에 then을 붙여서 async가 끝났을때 다른 작업을 시킬 수 있다.

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)
});

 

2) Async 함수의 오류처리

Async는 try, catch를 통해 오류처리를 할 수 있다. catch는 promise에서도 활용가능하다. 하지만 promise에서의 catch는 catch를 then에 붙여서 사용한다는 점이 다르다.

//async 오류처리
async function doSomething(msg) {
  try {
      const r = await promise1();
      console.log(r);
  } catch(e) {
      console.error(e);
  }
}

//promise 오류처리
function doSomething(msg) {
  return promise1()
      .then(r => {
      console.log(r)
      })
      .catch(e => {
          console.error(e)
      });
}

 

 

3) Promise의 병렬 실행

Async 속 await들을 한거번에 실행하고 싶다면 await을 걸때 Promise.all이라는 키워드를 넣어주게 되면 작업들을 동시에 실행한다. Promise.all은 promise 함수를 동시에 실행시키고 등록된 모든 함수가 마무리되면 결과값을 한꺼번에 반환한다.

promise1과 promise2를 실행하는데 각각 1초, 2초가 걸린다면 sync 예제에서는 3초가 parallel예제에서는 2초의 시간이 소요된다. sync라는 함수에서는 작업을 순차적으로 실행하고 parallel이라는 함수에서는 작업을 동시에 실행하기 때문이다. 

// 소요 시간 3초
async function sync() {
    const r1 = await promise1();
    const r2 = await promise2();
    console.log(r1, r2);
}

// 소요시간 2초
async function parallel() {
    const [r1, r2] = await Promise.all([
      promise1(),
      promise2(),
    ]);
    console.log(r1, r2);
}

 

 

 

 

 

**정리**

Callback 지옥 -> Promise chaining으로 해결

Promise 지옥 -> Async - Await으로 해결

 

현대 JavaScript에서는 대부분 가독성이 좋은 aysnc - await을 지향하지만 특정 상황에 맞는 비동기 코딩 방법들을 모두 구사할 줄 알아야 한다.

반응형