Front-End/JavaScript

[JavaScript] Callback / Promise / async await을 이용한 비동기 예제

KEMON 2021. 1. 6. 00:00
728x90

1. Callback 함수 예제

    - Callback 함수란 함수의 파라미터로 함수를 넣어 다음 함수로 실행 시키는것.
       -> 말이 조금 어려운데 예제를 보면 쉽게 이해 가능

function increaseAndPrint(n, callback){
  setTimeout(()=>{
    const increased = n + 1;
    console.log(increased);
    if(callback){
      callback(increased);
    }
  }, 1000);
}

increaseAndPrint(0, n => {
  console.log('끝'); //결과 : 1, '끝'
});

    - 위의 예제에서는 callback 함수에 n => {console.log('끝');} 함수를 넣은 것

2. Callback 지옥

    - Callback함수에 Callback함수를 계속 넣어 함수를 실행 시키는 것

    - 성능 저하의 가장 큰 원인이자 복잡한 구조

function increaseAndPrint(n, callback){
  setTimeout(()=>{
    const increased = n + 1;
    console.log(increased);
    if(callback){
      callback(increased);
    }
  }, 1000);
}

increaseAndPrint(0, n => {
  increaseAndPrint(n, n=>{
    increaseAndPrint(n, n=>{
      increaseAndPrint(n, n=>{
        increaseAndPrint(n, n=>{
          console.log('끝');   // 출력 결과 : 1,2,3,4,5,'끝'
        });
      });
    });    
  });
});

 

그래서 위와 같은 Callback 지옥을 해결하고자 Promise 함수를 사용한다.

3.Promise

    - Promise는 성공(resolve)할 수 있고 실패(reject)할 수 있다.

    - 아래의 예시는 성공(resolve)의 예시

 const myPromise = new Promise((resolve, reject) => {
  setTimeout(()=>{
    resolve('resolve');
  },1000);
 });

 myPromise.then(result => {
   console.log(result); //결과 : 'resolve'
 });

    - 위와 같이 성공을 하면 resolve함수를 사용하고 promise.then 구문을 통해서 다음 실행할 함수를 설정한다.

    - 아래의 예시는 실패(reject)의 예시

 const myPromise = new Promise((resolve, reject) => {
  setTimeout(()=>{
    reject(new Error());
  },1000);
 });

 myPromise.catch( e => {
   console.error(e);  // 결과 : Error
 });

    - 위와 같이 실패를 할 땐 reject함수를 사용하고 promise.catch 구문을 통해서 다음 실행할 함수를 설정한다. 

    - 아래의 예시에서는 Callback과의 차이를 명확히 알 수 있다

function increaseAndPrint(n){
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      const value = n+1;
      if(value === 5){
        const error = new Error();
        error.name = 'ValueIsFiveError';
        reject(error);
        return;
      }
      console.log(value);
      resolve(value);
    },1000);
  });
}

increaseAndPrint(0).then(n=>{
  return increaseAndPrint(n);
}).then(n=>{
  return increaseAndPrint(n);  //결과 : 1,2
})

    - 위의 then 구문을 보면 Callback 과는 달리 Promise 객체를 리턴해 주면 다시 then 구문을 사용할 수 있다.
       이런 장점으로 인해 코드가 훨씬 정리된다.

    - 그러나 Promise역시 then 구문으로 계속 이어가고 catch구문도 섞이다 보니 언제 에러가 났는지와 코드 분기 작업하기가 어려워 진다. 이러한 단점을 보안하기 위해 나온것이 async await

4. async await

    - 함수 앞에 async를 붙이고 함수 안에서 작동하는 Promise 객체에 then 대신 await을 붙인다.
    - async 함수의 return 값은 Promise 이다.

function sleep(ms){
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function process(){
  console.log('안녕하세요');
  await sleep(1000);
  console.log('반갑습니다');
  return true;
}

 process().then(value => {
     console.log(value); //결과 'true'
 });

    - then 대신 await을 붙임으로써 분기점 잡기가 쉬워졌고 그 사이에 로직을 작성하기도 편리한 구조가 되었다.

    - async 함수의 return 값은 Promise이므로 위의 예제에의 return 값(true)을 then을 이용해서 Promise 처리할 수 있다. 

    - 또한, 아래의 예제를 통해 언제 에러가 났는지 try - catch 구문으로 알 수 있다.

function sleep(ms){
  return new Promise(resolve => setTimeout(resolve, ms));
}
async function makeError(){
  await sleep(1000);
  const error = new Error();
  throw error;  //throw를 이용해서 Error를 던진다.
}
async function process(){
  try{
    await makeError(); 
  }catch(e){
    console.error(e); 
  }
}

 process(); 

 

예제에 대한 출처 : velopert

728x90