프로미스(Promise), 비동기 처리를 더 깔끔하게

정원·2023년 3월 28일

JS

목록 보기
1/2

2032.03.28 홍팍(유튜브) JS 프로미스

1. 콜백 지옥(callback hell)

  • 콜백 함수가 또 다른 콜백을 부르는 상황
  • 비동기 처리흐름 파일이 어려움

예시

아래 예시를 비동기방식으로 순서대로 처리해보자.

// 주문하기
function orderAPI(doNext) {
    setTimeout(() => {
        console.log("[주문] 완료");
        doNext();
    }, 1000);
}

// 결제하기
function pamentAPI(doNext) {
    setTimeout(() => {
        console.log("[결제] 완료");
        doNext();
    }, 1000);
}

// 배달하기
function deliveryAPI(doNext) {
    setTimeout(() => {
        console.log("[배달] 완료");
        doNext();
    }, 1000);
}

// 리뷰작성
function reviewAPI(doNext) {
    setTimeout(() => {
        console.log("[리뷰] 완료");
        doNext();
    }, 1000);
}

위의 코드를 활용해서 순서대로 호출을 진행해보면 아래와 같다.

orderAPI(() => {
    pamentAPI(() => {
        deliveryAPI(() => {
            reviewAPI(() => {
                console.log("== END ==");
            });
        });
    });
});

콜백을 활용한 비동기처리: 콜백 지옥 발생..
코드 파악이 어려움: 코드 흐름이 눈에 잘 들어오지 않음

2. 프로미스(Promise)

  • 콜백 지옥을 개선하는 객체
  • 비동기 처리 흐름을 파악하기 좋음
    MDN promise

프로미스 만들기

// 프로미스 만들기
const promise1 = new Promise((resolve, reject) => { // Promise는 파라미터로 resolve, reject를 받는다.
    // 비동기 처리
    setTimeout(() => {
        if (Math.random() < 0.5) {
            resolve("성공");
        } else {
            reject("실패");
        }
    }, 1000);
});

프로미스 호출

promise.then(성공시수행할_resolve콜백)
           .catch(실패시수행할_reject콜백)
           .finally(결과에상관없이무조건수행될콜백);

// 프로미스 호출
promise1.then((result) => { console.log(result)})
        .catch((err) => {console.log(err)})
        .finally(() => {console.log("== 끝 ==")})

3. 기존 콜백을 프로미스로 개선하기

  • 콜백 지옥은 기존 콜백을 직접호출해서 생김
  • 프로미스로 감싸면, 콜백 지옥을 없앨 수 있음

비동기 처리 코드를 프로미스로 감싸기

// 주문하기
function orderAPI() {
   return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (Math.random() < 0.8) {
                console.log("[주문] 완료");
                resolve();
            } else {
                reject("[주문] 실패");
            }
        }, 1000);
   })
}

// 결제하기
function paymentAPI() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (Math.random() < 0.8) {
                console.log("[결제] 완료");
                resolve();
            } else {
                reject("[결제] 실패");
            }
        }, 1000);
    })
}

// 배달하기
function deliveryAPI() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (Math.random() < 0.8) {
                console.log("[배달] 완료");
                resolve();
            } else {
                reject("[배달] 실패");
            }
        }, 1000);
    })
}

// 리뷰작성
function reviewAPI() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (Math.random() < 0.8) {
                console.log("[리뷰] 완료");
                resolve();
            } else {
                reject("[리뷰] 실패");
            }
        }, 1000);
    })
}

프로미스 호출

성공하면 주문-결제-배달-리뷰 순으로 프로미스가 실행되고 중간에 실패하면
catch문으로 넘어가서 실패가 나온 후에
마지막에는 무조건 finally가 실행된다.

orderAPI().then(() => { return paymentAPI() })
          .then(() => { return deliveryAPI() })
          .then(() => { return reviewAPI() })
          .catch((err) => { console.log(err) })
          .finally(() => { console.log("==끝==") });


---------------- 콜백 지옥 ---------------
getData(function(data) {
  getMoreData(data, function(moreData) {
    getMoreDataAgain(moreData, function(evenMoreData) {
      displayData(evenMoreData);
    });
  });
});

------------------ 프로미스로 변경 -------------------
getData()
  .then(function(data) {
    return getMoreData(data);
  })
  .then(function(moreData) {
    return getMoreDataAgain(moreData);
  })
  .then(function(evenMoreData) {
    displayData(evenMoreData);
  })
  .catch(function(error) {
    console.error(error);
  });

전체코드

// 주문하기
function orderAPI() {
   return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (Math.random() < 0.8) {
                console.log("[주문] 완료");
                resolve();
            } else {
                reject("[주문] 실패");
            }
        }, 1000);
   })
}

// 결제하기
function paymentAPI() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (Math.random() < 0.8) {
                console.log("[결제] 완료");
                resolve();
            } else {
                reject("[결제] 실패");
            }
        }, 1000);
    })
}

// 배달하기
function deliveryAPI() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (Math.random() < 0.8) {
                console.log("[배달] 완료");
                resolve();
            } else {
                reject("[배달] 실패");
            }
        }, 1000);
    })
}

// 리뷰작성
function reviewAPI() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (Math.random() < 0.8) {
                console.log("[리뷰] 완료");
                resolve();
            } else {
                reject("[리뷰] 실패");
            }
        }, 1000);
    })
}

orderAPI().then(() => { return paymentAPI() })
          .then(() => { return deliveryAPI() })
          .then(() => { return reviewAPI() })
          .catch((err) => { console.log(err) })
          .finally(() => { console.log("==끝==") });

// 콜백을 활용한 비동기처리: 콜백 지옥 발생..
// 코드 파악이 어려움: 코드 흐름이 눈에 잘 들어오지 않음
orderAPI(() => {
    paymentAPI(() => {
        deliveryAPI(() => {
            reviewAPI(() => {
                console.log("== END ==");
            });
        });
    });
});

// 프로미스 만들기
const promise1 = new Promise((resolve, reject) => { // Promise는 파라미터로 resolve, reject를 받는다.
    // 비동기 처리
    setTimeout(() => {
        if (Math.random() < 0.5) {
            resolve("성공");
        } else {
            reject("실패");
        }
    }, 1000);
});

// 프로미스 호출
// promise1.then(성공시_수행할_resolve_콜백)
//         .catch(실패시_수행할_reject_콜백)
//         .finally(결과에_상관없이_무조건_수행될_콜백);

promise1.then((result) => { console.log(result)})
        .catch((err) => { console.log(err)})
        .finally(() => { console.log("== 끝 ==")});

0개의 댓글