프론트엔드/JavaScript

Promise 기반 API

Ryuzy 2025. 4. 17. 21:40
728x90
반응형

1. 프로미스

자바스크립트의 프로미스(Promise)는 비동기 작업의 완료 또는 실패를 처리하기 위한 객체입니다. 프로미스는 주로 시간이 걸리는 작업(예: 네트워크 요청, 파일 읽기 등)을 처리할 때 사용되며, "미래에 결과를 약속한다"는 개념으로 동작합니다. new Promise()를 통해 생성하며, 내부에는 resolve와 reject라는 두 가지 콜백이 있어 작업이 성공하면 resolve, 실패하면 reject를 호출합니다. 이후 .then()으로 성공 결과를 처리하고, .catch()로 오류를 처리할 수 있으며, .finally()로 성공 여부와 상관없이 마지막에 실행할 코드를 작성할 수 있습니다. 이를 통해 콜백 지옥(callback hell)을 피하고, 코드 흐름을 더 읽기 쉽게 만들어 줍니다.

 

1. 콜백 지옥

콜백 지옥(Callback Hell)은 자바스크립트에서 비동기 작업을 순차적으로 처리하기 위해 콜백 함수를 중첩해서 사용할 때 발생하는 코드 구조입니다. 여러 개의 콜백 함수가 안쪽으로 계속 중첩되면서 코드가 "피라미드처럼 오른쪽으로 들여쓰기되어" 가독성이 떨어지고, 유지보수가 어려워지는 문제가 생깁니다. 예를 들어, 서버 요청 후 그 결과로 또 다른 요청을 하고, 그 결과로 또 다른 작업을 해야 할 때 각각의 작업을 콜백 안에서 처리하면 코드가 복잡해지고 오류 처리가 어려워집니다. 이런 문제를 해결하기 위해 Promise, 그리고 이후에는 async/await 같은 문법이 도입되어 보다 깔끔하고 직관적인 비동기 코드 작성을 가능하게 해주었습니다.

 

2. Promise의 3가지 상태

  1. 대기(Pending): 아직 작업이 끝나지 않은 상태
  2. 이행(Fulfilled): 작업이 성공적으로 끝난 상태 → resolve()
  3. 거부(Rejected): 작업이 실패한 상태 → reject()

 

3. 문법 구조

const promise = new Promise((resolve, reject) => {
  // 비동기 작업 수행
  if (성공조건) {
    resolve(결과값);
  } else {
    reject(에러값);
  }
});

promise
  .then(성공했을 때 실행할 코드)
  .catch(실패했을 때 실행할 코드)
  .finally(항상 실행할 코드);

 

console.log("요청을 보냅니다...");

const getData = new Promise((resolve, reject) => {
  setTimeout(() => {
    const success = true; // 성공 여부 (true 또는 false)로 변경하여 확인

    if (success) {
      resolve("서버에서 데이터를 성공적으로 받아왔습니다!");
    } else {
      reject("서버 요청 실패!");
    }
  }, 2000); // 2초 후 실행
});

getData
  .then((result) => {
    console.log("성공:", result);
  })
  .catch((error) => {
    console.log("실패:", error);
  })
  .finally(() => {
    console.log("작업 완료");
  });

 

function orderCoffee(menu) {
  console.log(`☕ ${menu} 주문을 접수했습니다. 잠시만 기다려주세요.`);

  const availableMenu = ["아메리카노", "카페라떼", "바닐라라떼"];

  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (availableMenu.includes(menu)) {
        resolve(`${menu}가 준비되었습니다! 맛있게 드세요 :)`);
      } else {
        reject(`죄송합니다. ${menu}는 판매하지 않습니다.`);
      }
    }, 2000);
  });
}

// 사용
orderCoffee("아메리카노")
  .then((message) => {
    console.log(message);
  })
  .catch((error) => {
    console.log(error);
  })
  .finally(() => {
    console.log("주문이 완료되었습니다.");
  });

 

function getBanana() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve('🍌')
        }, 1000)
    })
}

function getApple() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve('🍎')
        }, 3000)
    })
}

function getOrange(){
    return Promise.reject(new Error('오렌지 없음'))
}

getBanana()
    .then((banana) => getApple().then((apple) => [banana, apple]))
    .then(console.log)

// Promise.all: 병렬적으로 한번에 Promise들을 실행. 하나의 프로미스라도 실패하면 전체를 에러로 처리함
Promise.all([getBanana(), getApple()])
    .then((fruits) => console.log('all', fruits))

Promise.all([getBanana(), getApple(), getOrange()])
    .then((fruits) => console.log('all', fruits))
    .catch(console.log)

// Promise.race: 주어진 Promise중에 가장 빨리 수행된 것이 실행
Promise.race([getBanana(), getApple()])
    .then((fruits) => console.log('race', fruits))

// Promise.allSettled: 여러 프로미스를 병렬적으로 처리하되 하나의 프로미스가 실패해도 무조건 이행
Promise.allSettled([getBanana(), getApple(), getOrange()])
    .then((fruits) => console.log('allSettled', fruits))
    .catch(console.log)

 

 

2. async / await

async는 자바스크립트에서 비동기 작업을 보다 간결하고 읽기 쉽게 만들기 위해 사용하는 키워드입니다. 함수 앞에 async를 붙이면 해당 함수는 항상 프로미스를 반환하게 되며, 이 안에서 await 키워드를 함께 사용할 수 있습니다. await는 프로미스가 처리될 때까지 기다렸다가, 결과를 받아올 수 있도록 도와줍니다. 이를 통해 비동기 작업을 마치 동기 코드처럼 자연스럽게 작성할 수 있어, 복잡한 .then(), .catch() 체인을 피하고 코드 가독성을 높일 수 있습니다.

function orderCoffee(menu) {
  console.log(`☕ ${menu} 주문을 접수했습니다. 잠시만 기다려주세요.`);

  const availableMenu = ["아메리카노", "카페라떼", "바닐라라떼"];

  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (availableMenu.includes(menu)) {
        resolve(`${menu}가 준비되었습니다! 맛있게 드세요 :)`);
      } else {
        reject(`죄송합니다. ${menu}는 판매하지 않습니다.`);
      }
    }, 2000);
  });
}

// async/await 방식
async function startOrder() {
  try {
    const result = await orderCoffee("아메리카노"); // 주문
    console.log(result);
  } catch (error) {
    console.log(error);
  } finally {
    console.log("주문이 완료되었습니다.");
  }
}

startOrder();

 

 

728x90
반응형

'프론트엔드 > JavaScript' 카테고리의 다른 글

fetch  (0) 2025.04.18
브라우저에 데이터 저장하기  (0) 2025.04.17
JSON  (0) 2025.04.16
정규식  (0) 2025.04.16
이벤트  (0) 2025.04.16