IT's Jenna

Callback & Promise & async & await 본문

Backend/Backend 기본

Callback & Promise & async & await

developer Jenna 2021. 1. 27. 12:53

Javascript는 기본적으로 비동기 (Non-Blocking) 프로그래밍이다.

 

비동기 시스템이란, 동작이 스크립트가 작성된 순서대로 진행되는 것이 아니라 결과값이 먼저 나오는 순서대로 진행되는 것이다. 비동기 시스템은 주로 퍼포먼스가 극대화되어야 하는 웹/앱에서 많이 사용된다.

1. Non-Blocking 

fs.readFile('./file.md', (err, data) => {
    if (err) throw err;
    console.log('non blocking data : ',data);
});

console.log('wow')

//result
//wow
//non blocking data :  <Buffer 61 73 64 66 73 64 66>

스크립트가 작성된 절차대로 수행된다면 데이터가 먼저 출력되고 wow가 출력되겠지만, 비동기 방식은 그렇지 않다. console창에 wow를 출력하는 시간보다 데이터를 읽어오는 시간이 더 걸리기 때문에 위와 같은 결과가 나온다.

2. Callback

하지만, 스크립트를 작성하다보면 절차대로 진행되어야 하는 동작들이 생긴다. 이때 사용할 수 있는 방법 하나가 callback 함수이다. callback함수는 함수 안에서 실행되는 함수이다.

function sumFunction(num1, num2, callback){
    let result = num1+num2
    if('number' == typeof(result)){
        let error
        let message = result
        callback(error, message)
    } else {
        let error = 'is Not Number : ', result
        let message 
        callback(error, message)
    }
}


sumFunction(1, "abcd", 
    function(error, message){ // callback 함수
        console.log("error : ",error)
        console.log("message : ",message)
    }
)

//result
//error :  is Not Number : 
//message :  undefined

위의 예제에서 sumFunction을 만들 때 callback함수가 실행될 부분에 'callback'을 넣어준다. 실제로 함수를 실행시킬 때 callback함수의 내용을 입력해주면 해당 callback 함수가 실행되어야 할 때에 동작한다.

3. Callback Hell

위와 같이 callback 함수를 사용해서 스크립트를 작성하다보면 callback 안에 callback을 넣고 또 그 안에 callback을 넣는 callback hell에 빠지게 된다.

setTimeout(() => {
    console.log('sleep 2')
}, 3000);
setTimeout(() => {
    console.log('wake up! 1')
}, 1000);
console.log('eat 0');


setTimeout(() => {
    console.log('sleep')
     setTimeout(() => {
        console.log('wake up!')        
        setTimeout(() => {            
            console.log('eat');
        }, 1000);    
    }, 1000);    
}, 1000);

이때 Arrow function : () => 은 함수를 선언해주는 function()과 같다. 위와 같은 callback hell은 스크립트를 파악하기 쉽지 않다.

4. Promise 객체

Promise 객체를 활용해서 더욱 직관적으로 Non Blocking 코드를 제어할 수 있다. Promise가 비동기 코드를 제어할 수 있는 건 3가지 상태를 가지고 있기 때문이다. 3가지 상태는 다음과 같다.

 

  • Pending(대기) : 이행되거나 거부되지 않은 초기 상태
  • Fulfilled(이행) : 연산이 성공적으로 완료됨
  • Rejected(실패) : 연산이 실패함

이제 위 3가지 상태를 어떻게 활용하는지 알아보자. 제목에서 말한 것처럼 Promise는 객체이기 때문에 사용할 때 new를 이용해서 인스턴스화 하면서 선언해준다. 여기서 Promise가 가지고 있는 2개의 콜백 함수 매개변수가 있다. 바로 resolve와 reject이다.

 

  • Promise.resolve(value) : 이행된 promise값을 반환한다. (Fulfilled 상태)
  • Promise.reject(reason) : 거부된 promise를 반환한다. 디버깅용으로 에러를 체크하기 위해 사용한다. (Rejected 상태)

5. async & await

동기화를 시켜주기 위해 Promise와 함께 사용하는 것이 async와 await이다. 말 그대로 (async) 비동기를 (await) 기다린다는 의미이다. 사용 방법은 다음과 같다.

 

  1. Promise의 결과값을 받아와서 사용해야 하는 함수 앞에 async를 입력한다.
  2. Promise에서 반환되는 값 앞에 await를 입력한다.
  function promise(){    
    return new Promise((resolve, reject) => {
        setTimeout(function(){
          resolve("Success!");
        }, 250);
      });    
  }

  async function promisetest(){
      console.log('Test-Promise ' + await promise())
  }

  promisetest()
  
  //result
  //Test-Promise Success!

이때, 인스턴스화 한 Promise앞에 return을 붙여주는 이유는 promise()의 반환 값으로 resolve값을 내보내기 위해서다.

let myFirstPromise = new Promise((resolve, reject) => {
    setTimeout(function(){
      resolve("Success!"); // Yay! Everything went well!
    }, 250);
  });

  console.log('myFirstPromise : ',myFirstPromise)
  
  //result
  //myFirstPromise :  Promise { <pending> }

위와 같이 return값을 반환하지 않고 선언만 해준 Promise의 결과는 Promise 그 자체이다. 실제로 사용하고자 하는 promise의 resolve 또는 reject값을 얻기 위해서는 return을 사용하여 값을 반환해주는 것이 편리하다.

 

<참고>

developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve

velog.io/@ljinsk3/JavaScript-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC-Promise-%EA%B0%9D%EC%B2%B4

joshua1988.github.io/web-development/javascript/promise-for-beginners/#promise%EA%B0%80-%EB%AD%94%EA%B0%80%EC%9A%94

junil-hwang.com/blog/javascript-promise-async-await/

'Backend > Backend 기본' 카테고리의 다른 글

모듈화  (0) 2021.01.27
Database 상태변화  (0) 2021.01.27
Injection attak  (0) 2021.01.23
Express 환경 사용하기 3 - 라우팅  (0) 2021.01.20
Express 환경 사용하기 2 - 미들웨어  (0) 2021.01.19
Comments