본문 바로가기
Front-end/javascript

[JavaScript] 콜백지옥과 promise

by 잔디🌿 2023. 7. 25.

우선 콜백이 무엇인지 헷갈리시는 분은 아랫글을 참고해주세요

 

https://ethereal-coder.tistory.com/32

 

[JavaScript] 콜백함수

콜백함수는 함수를 매개변수로 받는 함수이다. 예시 코드 function day(time, morning, night){ if(time === "morning"){ morning(); //wakeUp이 출력 } else{ night(); //goToSchool이 출력 } } function wakeUp(){ console.log("wakeUp"); } f

ethereal-coder.tistory.com

 

Promise는 정말 자바스크립트를 공부하면서 고비라고 생각할 정도로 어려웠다. 

강의 영상을 정말 5번 정도 돌려봤는데도 이해가 안돼서 앞에 내용을 더 단단하게 이해하고 오니 바로 어느정도 습득했다!

혹시 promise가 너무 어렵다고 생각하시는 분들은 콜백지옥의 코드를 정확히 이해하고 다시 보는 것을 추천한다.

 

 

콜백지옥

 

function taskA(a,b,cb){
  setTimeout(() => {
    const res = a+b;
    cb(res);
    },3000);
    }
    
 function taskB(a,cb){
  setTimeout(() => {
    const res = a *2 ;
    cb(res);
    },3000);
    }
    
 function taskC(a,cb){
  setTimeout(() => {
    const res = a * 5;
    cb(res);
    },3000);
    }
    
    //호출하기
    
    //2와 3을 더하고, 여기에 2를 곱하고, 5를 곱하도록 호출하기
    
    taskA(2,3,(a_res) = >{
       console.log(a_res); // 2+3 출력
        taskB(a_res,(b_res) => {
          console.log(b_res); //(2+3) *2 출력
            taskC(b_res,(c_res) => {
              console.log(c_res); // (2+3)*2*5 출력
                    });
                 });
              });
              
              
   console.log("코드끝");

위 코드는 비동기적 함수가 있으므로, 코드 끝이 먼저 출력되고 나머지 것들이 차례로 출력된다. 

위와 같이 비동기함수의 리턴 값을 또 다른 비동기 함수에 전달하고 또 전달하고를 반복하면 콜백지옥에 걸린다. 이를 구원하기 위한 것이 promise이다.

 

Promise

 

비동기 함수가 가질 수 있는 상태는 세가지이다.

  • Pending (대기상태) 
  • Fulfilled (성공)
  • Rejected (실패)

대기상태에서 함수가 정상적으로 실행되면 성공, 아니면 실패이다.

여기서 함수가 성공한 것을 resolve되었다 라고 하고 , 실패한 것을 reject 되었다고 한다.

 

우선, 콜백함수만을 사용해서 받은 값이 양수인지, 음수인지 판단하는 코드를 만들었다.

function isPostive(number, resolve, reject){
  setTimeout(()=> {
    if(typeof number === "number"){

      //성공(resolve했을 때라고 가정)
      resolve(number >= 0 ? "양수" : "음수");
  
    }
    else{
    //실패(reject 했을 때라고 가정)
      reject("값이 잘못 입력되었습니다.");
    }
  },2000);
}

isPostive(
  5,
  (res) => {
    console.log("성공 : ", res);
  },
  (err) => {
    console.log("실패 : ",err);
  }
);

 이를 promise객체를 이용해서 다시 작성해보면

function isPostive(number){
  const exeutor = (resolve, reject) => {
    setTimeout(()=> {
      if(typeof number === "number"){
  
        //성공(resolve했을 때라고 가정)
        resolve(number >= 0 ? "양수" : "음수");
    
      }
      else{
        reject("값이 잘못 입력되었습니다.");
      }
    },2000);

  };

  const tesk = new Promise(exeutor); //isPositive호출되면 바로 여기로
  return tesk;
}

const res = isPostive( 100 ); // number을 넣은 객체를 반환

res.then((res) =>{
  console.log("성공 : ",res);
}
).catch((err) =>{
  console.log("실패 :", err);
})

이렇게 된다. res에 isPositive를 호출하여 isPositive 내에 함수를 promise에 넣어 리턴한 값을 받고,

res.then(성공했을 때 함수).catch(실패했을 때 함수) 로 호출하면 위와 같은 기능을 하는 코드가 만들어진다.

 

그럼, 글 위쪽에서 콜백지옥을 설명했던 코드를 promise를 이용해서 짜보자.

 

function taskA(a){
  return new Promise((resolve,reject) => {// promise 객체 리턴
    setTimeout(() => {
      const res = a+b;
      resolve(res);
      },3000);
  });
    }
    
 function taskB(a){
   return new Promise((resolve,reject) => {// promise 객체 리턴
    setTimeout(() => {
      const res = a *2 ;
      resolve(res);
      },3000);
      });
  }

function taskC(a){
  return new Promise((resolve,reject) => {// promise 객체 리턴
    setTimeout(() => {
      const res = a * 5;
      resolve(res);
      },3000);
      });
  
    }

    taskA(2,3)                       //taskA의 promise 리턴됨
    .then((a_res) => {
      console.log("A result : ",a_res);
      return taskB(a_res);
    })                               //taskB의 promise 리턴됨
    .then((b_res) => {
      console.log("B result : ",b_res);
      return taskC(b_res);
    })                              //taskC의 promise 리턴됨
    .then((c_res) =>{
      console.log("C result", c_res);
    })

위에 있는 task들은 매개변수로 하나의 정수로 만들고, promise객체를 리턴하도록 한다. 

또한 호출하는 부분은 위와 같이 promise객체가 리턴될 때마다 then 을 이용해서 다음에 실행할 함수를 만들어준다. 이때 then이 여러개라 어색하다고 느낄 수 있는데, 주석 친 부분에서 promise 객체가 리턴되고 then은 이 각각의 객체에 대한 것이니까 문제가 없는 코드이다.

 

이런 방식으로 코드를 짜면, 가독성이 높아진다는 장점도 있지만, 

 

const task =  taskA(2,3) //상수를 만들어 여기다가 promise객체 받음
    .then((a_res) => {
      console.log("A result : ",a_res);
      return taskB(a_res);
    });

    console.log("안녕하세요"); // 다른코드
    
    task.then((b_res) => {  //위에서 받은 promise객체에 then으로 호출
      console.log("B result : ",b_res);
      return taskC(b_res);
    })
    .then((c_res) =>{
      console.log("C result", c_res);
    })

위의 코드처럼 콜백 함수들을 실행하는 중간에 다른 코드를 넣을 수 있다는 장점이 있다.

'Front-end > javascript' 카테고리의 다른 글

[JavaScript] API 호출  (0) 2023.07.30
[JavaScript] async와 await  (1) 2023.07.28
[JavaScript] 동기, 비동기  (1) 2023.07.18
[JavaScript] spread 연산자  (0) 2023.07.17
[JavaScript] 비 구조화 할당  (1) 2023.07.17