FE develop/Javascript

자바스크립트 비동기 이해하기 - (3.2) Promise를 더 알아보자

hoj0806 2025. 4. 18. 12:14

2025.04.16 - [FE develop/Javascript] - 자바스크립트 비동기 이해하기 - (3.1) Promise란?

 

지난 포스트에 이어 이번 글에서는 Promise에 대해 더 깊이 알아보겠습니다.
특히 Promise ChainingFetch API, 그리고 이를 활용한 간단한 실전 예제도 함께 다뤄보겠습니다.

 

🔗 Promise Chaining이란?

Promise 객체의 .then() 메서드는 새로운 Promise를 반환합니다.
따라서 .then()을 계속 연결해 체인처럼 이어지는 구조로 만들 수 있는데, 이를 Promise Chaining이라고 합니다.

이 기법을 활용하면, 비동기 작업을 순차적으로 실행할 수 있고, 콜백 지옥(Callback Hell)을 피할 수 있어 코드가 훨씬 깔끔해집니다.

 

예를 들어 다음과 같은 코드가 있습니다

function getData() {
    const promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            const data = { name: '철수' }

            if (data) {
                console.log("네트워크 요청 성공")
                resolve(data)
            } else {
                reject(new Error("네트워크 문제가 발생했습니다"))
            }
        }, 1000)
    })
    return promise
}

getData()
    .then(() => getData()) // 첫 번째 작업이 완료된 후 두 번째 작업 실행
    .then((data) => {
        console.log(data)
    })

 

 

또한 .then() 안에서 값을 리턴하면, 그 값은 자동으로 Promise.resolve()로 감싸진 상태로 다음 .then()으로 전달됩니다

function getData() {
    const promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            const data = { name: '철수' }

            if (data) {
                console.log("네트워크 요청 성공")
                resolve(data)
            } else {
                reject(new Error("네트워크 문제가 발생했습니다"))
            }
        }, 1000)
    })
    return promise
}

getData()
    .then(() => getData()) // 첫 번째 작업이 완료된 후 두 번째 작업 실행
    .then((data) => {
        console.log(data)
    })

 

🌐 Fetch API 사용법

fetch() 함수는 자바스크립트에서 데이터를 받아올 때 사용하는 API로, Promise를 반환합니다.

다음은 기본적인 사용 예제입니다

fetch("https://jsonplaceholder.typicode.com/users")
    .then((response) => {
        return response.json() // 응답을 JSON 형식으로 변환
    })
    .then((data) => {
        console.log(data) // 실제 데이터 출력
    })
    .catch((error) => {
        console.error(error) // 에러 처리
    })
    .finally(() => {
        console.log('마무리 작업') // 성공, 실패와 관계없이 항상 실행
    })

 

  • fetch()는 네트워크 요청을 보낸 후 Response 객체를 반환합니다.
  • response.json()은 비동기적으로 JSON 파싱을 수행하며, 이 역시 Promise를 반환합니다.

💡 실전 예제: 로그인 → 장바구니 → 결제

실제 사용 시나리오처럼 여러 비동기 작업을 순차적으로 처리하는 예제를 만들어보겠습니다.

 

// 1. 로그인
function login(username) {
    return new Promise((resolve, reject) => {
          setTimeout(() => {
            if(username) {
                resolve(username)
            } else {
                reject(new Error("아이디를 입력해주세요"))
            }
        }, 1000);        
    })
}


// 프로미스를 이런식으로 사용가능
// login.then((data) =>).catch((error))

// 2. 장바구니에 상품 추가
function addToCart(product) {
    return new Promise((resolve, reject) => {
          setTimeout(() => {
              if(product) {
                  resolve(product)
              } else {
                  reject(new Error("상품을 넣어주세요"))
              }
        }, 1000);       
    })
 
}

// 3. 결제
function makePayment(cardNumber, product) {
    return new Promise((resolve, reject) => {
          setTimeout(() => {
      if(cardNumber.length !== 16) {
          reject(new Error("잘못된 카드 번호입니다"))
      }
        resolve(product)
  }, 1000);
        
    })

}

 

 

📦 Promise Chaining을 활용한 흐름 처리

login('홍길동')
    .then((username) => {
        console.log(`${username}님 환영합니다`)
        return addToCart('감자')
    })
    .then((product) => {
        console.log(`${product}를 장바구니에 넣었습니다`)
        return makePayment('1231231231231231', product)
    })
    .then((product) => {
        console.log(`${product}를 구매했습니다`)
    })
    .catch((error) => {
        console.error("에러 발생:", error.message)
    })
    .finally(() => {
        console.log("모든 프로세스가 완료되었습니다")
    })

 

이처럼 Promise Chaining을 이용하면 비동기 로직을 순차적으로 깔끔하게 처리할 수 있습니다.
에러 처리도 중간에 .catch() 하나만 두면, 어디서 문제가 발생하든 한 번에 처리할 수 있어 더욱 효율적입니다.