08. Promise 패턴과 Fetch API

2025. 7. 13. 17:44[우리FIS Academy] 학습일지/Front-End


 

 

JavaScript를 통해 비동기 작업을 처리할 수 있다는 걸 학습했다.

그 중에서도 "콜백 패턴"을 이용하여 비동기 처리하는 방법에 대해서 직접 보았는데, 이는 여러가지 단점이 존재했다.

  • 복잡한 중첩 구조와 콜백 지옥
  • 복잡한 예외처리 등 . . .

그렇다면, 비동기 처리를 위한 또 다른 방법이 있을까?

 


 

 

Promise

Promise란, 어떤 작업의 처리 결과에 대한 값이 담길 객체를 말한다.

어떤 작업을 시작하는 시점에서는 해당 작업이 성공할 수도, 실패할 수도 있기 때문에 알 수 없는 값(pending)을 가지고 있는 Proxy 객체가 바로 프로미스(promise)이다. (Java의 Future와 비슷한 개념이다)

 

해당 객체의 결과 값은 미래의 어느 시점에 성공/실패 중 하나의 형태로 응답받게 된다. 이것이 바로 비동기 처리에서 활용할 수 있는 이유이다. 비동기 작업은 현재 실행되는 것이 아니기 때문에 그 결과를 알 수 없고 그에 대한 결과를 처리하는 것이 어렵다. 하지만, Promise 객체와 같이 결과가 담길 값을 미리 받아옴으로써 이에 대한 사유를 처리할 수 있게 된다.

 

다만, 최종 결과 '값'을 반환하는 것은 아니고 미래의 어떤 시점에 결과를 제공하겠다는 '프로미스 객체'를 반환하는 것이긴 하지만 . . 

 

 

Promise 객체의 상태

  • 대기 (pending) : 초기 상태
  • 이행 (fulfilled) : 연산이 성공적으로 완료된 상태
  • 거부 (rejected) : 연산이 실패한 상태

 

promise의 객체의 결과가 결정되는 단계/과정

 

 

 

JavaScript에서의 Promise

그렇다면 자바 스크립트에서는 Promise를 어떻게 사용할 수 있을까?

주로 외부 API를 활용하는 비동기 처리 작업에 사용이 된다. Promise를 통해 비동기 작업의 결과를 미리 만들어 둘 수 있고, 그에 따른 성공과 실패 상황을 미리 예측하고 적절한 처리를 해둘 수 있기 때문이다.

 

앞서 학습했던 콜백 패턴으로 JavaScript의 비동기 처리 작업을 했을 때, 복잡했던 예외/ 후속 처리를 Promise를 사용하면 훨씬 간단하게 작성할 수 있게 된다!

 

 

Promise 객체 사용 방법

const promise = new Promise((resolve, reject) => {}); // 인자로 executor 필요
console.log(promise);  // 이 시점엔 아직 "pending" 상태

 

생성 직후의 프로미스 객체는 pending 상태를 가진다

 

  • State: 작업의 진행 상태로 pending/fulfilled/ rejected 값을 가진다
    • fulfilled: .then()으로 처리 결과 값을 받을 수 있음
    • rejected: .catch()로 실패 이유를 받을 수 있음
  • Result: 작업 성공/실패시 반환하는 정보

 

 

Resolve와 Reject 콜백

작업이 성공한 경우, resolve(응답 결과 값) 함수를 호출한다. 또 작업이 실패한 경우, reject(실패 이유) 함수를 호출한다.

const promise1 = Promise.resolve(123);

promise1.then((value) => {
  console.log(value);
  // Expected output: 123
});


Promise.reject(reason); // reject 한 이유 reason

 

 

Promise를 활용한 후속 처리

1. then(callback)

비동기 처리가 성공하면, 실제로 동작하는 것은 then() 의 매개변수로 전달된 콜백 함수가 호출이 된다.

resolve()의 인자로 들어가는 값을 then()의 매개변수를 통해 가져올 수 있다.

const promise1 = new Promise((resolve, reject) => {
  resolve("Success!");
});

promise1.then((value) => {
  console.log(value);
  // Expected output: "Success!"
});

 

 

2. catch(callback)

비동기 처리가 실패하면, catch()의 매개변수로 전달된 콜백 함수가 호출이 된다.

const promise1 = new Promise((resolve, reject) => {
  throw new Error("Uh-oh!");
});

promise1.catch((error) => {
  console.error(error);
});
// Expected output: Error: Uh-oh!

 

 

3. finally(callback)

비동기 처리 결과에 상관없이, 무조건 한 번은 호출이 된다.

function checkMail() {
  return new Promise((resolve, reject) => {
    if (Math.random() > 0.5) { 			// 성공했을 때,
      resolve("Mail has arrived");
    } else { 							// 실패했을 때
      reject(new Error("Failed to arrive"));
    }
  });
}

checkMail()
  .then((mail) => {
    console.log(mail);
  })
  .catch((err) => {
    console.error(err);
  })
  .finally(() => {						// 여부에 관계없이 무조건 실행
    console.log("Experiment completed");
  });

 

 

 

이처럼 후속처리를 위해 각각의 메서드를 체이닝하여 호출할 수 있다.

이는 해당 메서드들이 Promise 객체를 반환하기 때문이다!

 


 

Fetch API

앞서 콜백 패턴을 활용해서 요청과 응답을 처리할 수 있는 XMLHttpRequest API에 대해 알아보았다.

하지만 콜백 패턴의 여러 단점을 보완하기 위해 프로미스라는 개념도 등장하였는데, 해당 API를 더 보완할 수는 없을까?

 

바로 Fetch API는 프로미스 패턴을 활용하여 요청과 응답을 처리할 수 있다!

fetch() 메서드를 사용하여 네트워크의 리소스를 쉽게 비동기적으로 획득하여 사용할 수 있다.

 

즉, 콜백 기반의 API인 XHR과 달리, 프로미스 기반의 API인 Fetch가 대체제로 등장한 것이다. 이는 CORS를 포함하기도 하여, 더욱 편리한 통신을 가능하게 해 준다.

 

 

Fetch()

fetch() 메서드는 Promise 객체를 반환해 주며, 직접 promise 객체를 생성하지 않아도 된다.

따라서 then, catch 등 간편하게 체이닝을 활용할 수 있다.

 

async function logJSONData() {
  const response = await fetch("http://example.com/movies.json");
  const jsonData = await response.json();
  console.log(jsonData);
}

 

1. fetch(가져오고자 하는 리소스의 경로)

하나의 인수만 받아 fetch() 메서드를 통해 요청을 전송한다.

 

2. response

요청을 통해 받아온 응답은 response 객체로 표현한다.

 

3. json()

response 객체로부터 JSON 응답을 가져와야 하는데, 이는 바로 접근할 수는 없다. response는 HTTP 응답 전체를 나타내는 객체이므로, json() 메서드를 통해 본문의 텍스트를 JSON으로 파싱해야 한다.

 

 

 

 


 

Async & Await 키워드

 

콜백 패턴을 이용한 통신에 단점을 보완하고자, 프로미스 패턴을 이용한 통신이 등장하였다.

하지만, 이 프로미스 패턴에서도 본질적으로는 콜백 함수가 사용된다. 그렇기 때문에 비동기 작업이 복잡해지면, 체이닝도 길어지도 가독성이 떨어지게 된다.

 

이때 등장한 키워드가 바로 Async, Await 키워드이다.

 

Async 키워드를 붙여 비동기 작업을 처리하는 함수임을 알려주고, Await 키워드를 붙여 비동기 작업이 완료된 이후 다음 작업으로 넘어가게끔 설정하는 것이다. 그럼 마치 동기적으로 동작하는 것 처럼 가독성을 높일 수 있다. 물론 Async 함수의 반환 값은 프로미스 객체이기 때문에, 자체적으로도 then 핸들러를 사용할 수도 있다!

 

 

fetch(url)
    .then(response => response.json())
    .then(json => {
      console.log(json);
    })

 

위 then 핸들러 방식을 아래 awai 방식으로 변환할 수 있다.

async function a(){
	const response = await fetch(url);
    const json = await response.json();
    console.log(json);
}

a();

 

훨씬 더 직관적이고 가독성있는 코드로 작성할 수 있게 해준다!

 

 

 

 

 

 

 


 

요약

JavaScript로 비동기 처리를 위한 패턴 2가지를 살펴보았다.

 

1. 콜백 패턴

가독성, 후속/예외처리 어려움 등 여러가지 단점 존재

 

2. 프로미스 패턴

후속/예외처리를 보완하기 위한 프로미스 객체 활용 패턴

 

JavsScript로 네트워크 통신을 위한 2가지 방식도 살펴보았다.

 

1. 콜백 패턴을 활용한 API - XMLHttpRequest

2. 프로미스 패턴을 활용한 API - Fetch 

 

+ 추가적으로, 가독성을 높이기 위한 키워드 async와 await

 

 

 


참조
promise (link)
async,await (link)

'[우리FIS Academy] 학습일지 > Front-End' 카테고리의 다른 글

10. Test Code  (0) 2025.07.13
09. Testing  (0) 2025.07.13
07. CORS (Cross-Origin Resource Sharing)  (1) 2025.07.13
06. 콜백함수(CallBack)  (1) 2025.07.13
05. 자바스크립트의 비동기 처리  (1) 2025.07.13