Ryu.log

[ NodeJS 05 ] 콜백과 프로미스(Promise) 비교 본문

Prev-content

[ NodeJS 05 ] 콜백과 프로미스(Promise) 비교

류뚝딱 2018. 7. 24. 11:04


01. Callback

아래 코드들 중 Users.findOne , Users.update , Users.remove함수들은 콜백을 설명하기위해 예시로 작성된 코드이다.

Users.findOne('juno', (err,user)) => {
  if(err){
    return console.error(err);
  }
  console.log(user);
});

만약 이런 코드가 있다고 치자, 콜백형식으로 코드를 작성했을때 위 코드와 같이 구성된다.

위 코드는 Users라는 Data에서  juno라는 이름을 찾아서 응답으로 기다린다.


보통 이렇게 콜백을 쓰는 이유는 위 코드가 비동기(논 블러킹)으로 작동하기 때문이다. 아래 코드를 보자

Users.findOne('juno', (err,user)) => {
  if(err){
    return console.error(err);
  }
  console.log(user);
});
console.log('다 찾았니?')

이렇게 아래쪽에 console을 찍어보면, 

findOne함수안에 들어있는 console.log(user)보다 console.log('다 찾았니?')가 먼저 실행될 것이다.

보통 콜백을 쓰는 경험에 따르면 User.findOne('juno', (Callback Function...... 이런 코드들은, 

네트워크를통해 데이터베이스에 접근하여 쿼리를 날리는등의 작업을 처리하는데,

이 과정에서 시간을 소요하며, 소요시간이 얼마나 걸릴지 모르기 때문에

논블러킹 방식으로 요청만 보내놓고, 다음 코드를 실행한다.


그 뒤에 데이터베이스에서 juno를 찾았다면 이벤트루프로 콜백을 넣어준다.

찾는 과정에서 에러가 있었다면 if문을 통해 에러를 발생시키고

찾았다면 console.log(user)를 찍는다.


그렇기 때문에 위쪽 console.log('user')보다, 아래 console.log('다 찾았니?')가 더 먼저 찍히는것이다 


이 같은 코드가 흔이 보던 콜백의 모습이다.


그런데 이런식으로 콜백을 사용하면 단점이 있다. 순서가 굉장히 애매해지는 것이다.

코드를 신나게 쓰더라도 실행순서를 못찾아서 코드가 어떻게 흘러가는지 파악하기가 어렵다. 아래 코드를보자.

Users.findOne('juno', (err,user)) => {
  if(err){
    return console.error(err);
  }
  console.log(user);
  Users.update('juno', 'jjuno', (err, updateUser) => {
    if(err){
      return console.error(err);
    }
    console.log(updatedUser);
    User.remove('jjono', (err, removedUser) => {
      if(err){
        return console.error(err);
      }
      console.log(removedUser);
      //....콜백 안에 콜백 콜백안에 콜백 반복....
    });
  })
});
console.log('다 찾았니?')

이런식으로 콜백안에 콜백함수가 존재하고 또 존재하고 이런식으로 끝없이 들어갈 수가있는데, 이것을 Callback Hell(콜백 지옥)이라한다.

이런식으로 코드가 계속진행되면 코드가 굉장히 보기 힘들어지고 어디서 난 오류인지 찾기도 어려워진다.


이런 콜백지옥을 벗어나기위해 아래와 코드와같은 형식으로 콜백지옥을 벗어나려는 노력을 했다.

const afterRemove = (err, removedUser) => {
  console.log(removedUser);
}

const afterUpdate = (err, updated) = > {
  console.log(updatedUser);
  User.remove('jjuno', afterRemove);
}

Users.findOne('juno', (err,user)) => {
  if(err){
    return console.error(err);
  }
  console.log(user);
  Users.update('juno', 'jjuno', afterUdate);
});
console.log('다 찾았니?')

이런식으로 콜백지옥을 벗어나기 위한 노력을했지만 여전히 조금 애매하다, 코드가 한눈에 보이지 않는데다가 코드가 역순이되버려서 가독성이 상당히 나빠진다.



2. Promise

콜백지옥을 벗어나려던 이러한 노력은, ES6Promise를 만나면서 조금더 코드가 세련되어졌다. 다른 언어에서 따온 것인데

Promise가 나옴으로 써 JavaScriptNode.js의 비동기는 차원이 달라졌다. 그동안 bluebird나 jQuery 같은 라이브러리에서도 일부 구현하여 지원하였지만,

이제는 JavaScript ES6에서 공식지원 한다. 아래 코드와 위의 콜백 방식을 비교해보자,

Users.findOne('juno')
  .then((user) => {
    console.log(user);
    return User.update('juno', 'jjuno');
  })
  .then((updatedUser) => {
    console.log(updatedUser);
    return User.remove('jjuno');
  })
  .then((removedUser) => {
    console.log(removeUser);
  })
  .catch((err) => {
    console.error(error);
  });
console.log('다 찾았니?');

위 코드를 보자, 기존 콜백코드와 비교해서 깊이가 깊어지지도 않고 유지되면서, 아래로 순차적으로 비동기를 진행한다.

위의 콜백방식보다 훨씬 코드의 가독성이 올라갔다, 그래서 Promise가 처음 나왔을 때 엄청난 인기를 끌었다.


다음 시간에는 then()이나 catch()이런것들이 무엇인지 이 Promise를 전격 분해해보자. 

Comments