본문 바로가기
JavaScript & jQuery

JavaScript - Callback & Promise & Async/Await

by devLog by Ronnie's 2021. 6. 27.

JavaScript - Callback & Promise & Async/Await 

 

자바스크립트는 다른 언어들과는 다르게 싱글 스레드를 사용하는 언어이다.

이 말은 즉, 한번에 한개의 일만 순차적으로 처리한다는 말과 같다.

 

병렬 처리를 할 수 없어 자바스크립트에서는 비동기 non-blocking 방식을 통해 해결한다.

 

이 방식을 쉽게 예를 들면 식당에서 손님과 종업원과 요리사가 있다고 했을때 동기 방식에서는 손님한명한테 주문을 받고 요리사에게 주문을 건내주어 음식이 나올때까지 다른 손님의 주문을 받지 않고 기다렸다가 음식이 나오면 갖다주고 다음 주문을 받는 것이라 생각하면 이해가 쉽다. 비동기 방식은 반대로 주문을 받고 요리사에게 주문을 알려주고 음식이 나올때까지 기다리는 것이 아니고, 다음 주문을 받으러 가는 것이다.

 

이러한 특성을 이해하고 봐주면 이해가 훨씬 빠를 것이다.

 

본론으로 들어가 Callback & Promise & Async/Await 에 대해 알아보자.

 

Callback

자바스크립트에서는 함수의 인자값으로 함수를 받아들일 수 있다. 이렇게 받아들인 함수를 다시 호출하는 기능을 콜백이라고 부른다.

function add5(a, callback) {
  setTimeout(() => callback(a + 5), 100)
// 100ms가 지난 후 함수로 입력받은 callback에 a + 10값을 다시 입력하여 callback함수 호출
}
add5(10, function (res) { // add5가 입력받는 callback함수 정의 부분
  console.log(res)
});

Callback Hell

이름에서 예상이 가능하다. 콜백헬이란 비동기 처리 로직을 위해 콜백 함수를 연속해서 사용할 때 발생하는 문제이다.

콜백함수가 몇번 안되면 크게 상관은 없겠지만 그 수가 많아진다면 깊어지는 Depth와 에러처리. 유지보수의 문제에서 상당히 취약한 부분이 많아진다. 아래 그림을 보면 이해가 빠를것이다.

 

이러한 문제점을 해결할 수 있는 방안으로 Promise 와 Async/Await을 사용하면 된다.

 

Promise

Promise를 사용하기 위해서는 먼저 객체를 생성을 해주어야 한다. 인자값으로는 resolve와 reject를 인자로 갖는 콜백함수를 넣어준다. 이렇게 만든 promise에 then과 catch를 붙여 resolve가 호출 된다면 then이 실행되고 reject가 실행되면 catch가 실행된다.

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.error(error); // 실패(reject)한 경우 실행 
});

아래의 예시를 보면 콜백함수가 여러개가 들어갔지만 depth가 깊어지지 않아 가독성이 훨씬 좋아졌으며, 콜백헬에서와 같이 예외처리 구문을 콜백에 갯수에 따라 증가하는 것이 아닌 catch문 하나로 에러를 잡을 수 있다는 큰 장점이있다.

promise
    .then( (message) => {
        return new Promise( (resolve, reject) => {
            resolve(message2);
        });
    })
    .then( (message2) => {
        console.log(message2);
        return new Promise( (resolve, reject) => {
            resolve(message2);
        });
    })
    .then( (message3) ) =>{
        console.log(message3);
    })
    .catch( (error) => {
        console.error(error);
    })
});

 

Async/Await

Node.js 버전 7.6부터 구현된 기능이다. Async/Await을 사용하면 Promise에 비해 쉽게 비동기적인 상황을 표현할 수 있다.

아래는 Async/Await에 기본 문법이다.

async function 함수명() {
  await 비동기_처리_메서드_명();
}

이때 주의할 점은 비동기 처리 메서드가 꼭 promise객체를 반환해야 await가 의도한 대로 동작한다는 것이다.

 

Async/Await에서의 예외처리 방법은 아래와 같은 방법이 있다.

async function f2() {
  const a = await add10(10).then(res => res);
  const b = await add10(a).catch(err => err);
  console.log(a, b)
}
f2();

add10(a)는 프로미스객체를 리턴하기 때문에 바로 catch문을 사용할 수 있다.

 

또는 아래와 같이 기존과 같은 방식으로 try-catch를 이용할수도 있다.

async function f3() {
  try {
    const a = await add10(10)
    const b = await add10(a)
    console.log(a, b)
  } catch(err) {
    console.log(err)
  }
}
f3();

 

댓글