Promise

GW·2024년 7월 11일

Promise

Promise는 자바스크립트에서는 비동기 실행을 동기화하는 구문으로 사용한다.
Promise의 뜻인 약속을 떠올리면 Promise의 개념을 이해하기 편하다

현실세계에서 약속은 미래에 어떤것을 할 거라고 정의하는 거다. 약속은 이행, 거절, 대기 세가지의 상태를 가질수있다.
Promise는 객체이므로 new 연산자로 인스턴스 생성이 가능하다.

Promise예제

const { reject } = require("lodash");

const DB = [];

function saveDB(user) {
  const oldDBSize = DB.length;
  DB.push(user);
  console.log(`save ${user.name} to DB`);
  return new Promise((resolve, reject) => { //콜백대신 Promise 객체 반환
    if (DB.length > oldDBSize) {
      resolve(user); // 성공시 유저정보 반환
    } else {
      reject(new Error("save DB Error!")); //실패시 에러 발생
    }
  });
}

function sendEmail(user) {
  console.log(`email to ${user.email}`);
  return new Promise((resolve) => {	//Promise 객체를 반환, 실패 처리 없음
    resolve(user);
  });
}

function getResult(user) {
  return new Promise((resolve, reject) => { // Promise객체 반환
    resolve(`success register ${user.name}`);// 성공 시 성공 메시지와 유저명 반환
  });
}
function registerByPromise(user) {
  //2. 비동기 호출이지만 순서를 지켜서 실행
  const result = saveDB(user).then(sendEmail).then(getResult);
 //3. 아직 완료되지 않았으므로 지연 상태
  console.log(result);
  return result;
}

const myUser = { email: "andy@asd", password: "1234", name: "andy" };
const result = registerByPromise(myUser);
// 결과값이 Promise이므로 then()메서드에 함수를 넣어서 결과값을 볼 수 있음
result.then(console.log);


//위코드와 동일
(Promise all)
const myUser = { email: "andy@asd", password: "1234", name: "andy" };
allResult = Promise.all([saveDB(myUser), sendEmail(myUser), getResult(myUser)]);
allResult.then(console.log);

Promise 문제점

  • promise 객체는 콜백보다는 확실히 편리하다.
  • 다만, then(), catch()함수를 연결하는 체이닝 방식을 사용하기가 만만하지는 않다.

복잡한 프로미스 예제

  • 현재 상영 영화 순위를 20위까지보여주는 코드를 구현.
const axios = require("axios");

const url =
  "http://raw.githubusercontent.com/wapj/jsbackend/main/movieinfo.json";

axios
  .get(url)
  .then((result) => {
    if (result.status != 200) {
      throw new Errpr("요청에 실패");
    }
    if (result.data) {
      return result.data;
    }
    throw new Error("데이터가 없습니다.");
  })
  .then((data) => {
    if (!data.articleList || data.articleList.size == 0) {
      throw new Error("데이터가 없습니다.");
    }
    return data.articleList;
  })
  .then((articles) => {
    return articles.map((article, idx) => {
      return { title: article.title, rank: (idx += 1) };
    });
  })
  .then((results) => {
    results.forEach((movieInfo, index) => {
      console.log(`[${movieInfo.rank}] 위 ${movieInfo.title}`);
    });
  })
  .catch((err) => { // 중간에 발생한 에러를 여기서 처리 
    console.log("<<err>>");
    console.error(err);
  });

문제점 및 대안 찾기

  • 프로미스가 콜백보다는 깔끔한코드를 유지할 수 있지만, 잘못 사용될 수 있는 여지가 남아있다
  • 첫 번째 예로는 프로미스의 then() 함수에 성공시와 실패시 처리할 함수둘 다 넘기는경우
  • 이렇게 둘다 넘기면 프로미스는 장식에 불과, 좋은 방법은 catch()함수로 예외처리

1.첫번째 코드

function myWork(work) {
  return new Promise((resolve, reject) => {
    if (work === "done") {
      resolve("게임 가능");
    } else {
      reject(new Error("게임 불가능 "));
    }
  });
}

//1. 콜백과 다를게 없음
myWork("done").then(
  function (value) {
    console.log(value);
  },
  function (err) {
    console.error(err);
  });

//2 좋은 코드
myWork('done')
  .then(function(value){console.log(value)})
  .catch(function(err){console.error(err)});

2.두번째 코드

function myWork(work) {
  return new Promise((resolve, reject) => {
    resolve(work.toUpperCase())
  });
}

function playGame(work){
    return new Promise((resolve, reject)=>{
        if(work === 'DONE'){
            resolve('Go Play Game')
        }
        else{
            reject(new Error("DONE!"))
        }
    })
}

// 프로미스를 중첩해서 사용
myWork('done')
    .then(function(result){
        playGame(result).then(function(val){
            playGame(result).then(function(val){
                console.log(val);
            })
        })
    })

    myWork('done')
        .then(playGame)
        .then(console.log)
  • 1.코드에서 프로미스를 중첩해서 사용했다.
    • 콜백시 가독성이 안좋은데 콜백보다 더 가독성이 나쁜 코드로 변함
  • 2.이전보다 훨씬 깔끔한 코드가 되었다

조금더 좋은방법이 없을까?

  • javascript가 발전하면서 사용하기 까다로운 Promise를 사용이 간편한 async await로 발전시켯다.

0개의 댓글