본문 바로가기

React

[JavaScript]💡3. 비동기 처리의 핵심, Promise와 async/await

0. 들어가면서

비동기 프로그래밍은 현대 웹 개발에서 필수적인 개념입니다. 얼마 전 포스팅에서도 뉴스 리스트 페이지를 개발하며 마주쳤던 문제인 비동기 제어 처리를 하는 법에 대해 포스팅 했지만 이번엔 온전히 그 개념만을 살펴보도록 하겠습니다. JavaScript에서 비동기 처리를 다루는 대표적인 방식으로 Promiseasync/await.

이번 포스팅에서는 이 두 개념을 비교하고, 어떻게 활용하는 것이 좋은지 알아보겠습니다.

 

 

 


1. Promise란?

Promise는 비동기 작업을 처리할 때 사용하는 JavaScript 객체로, 성공 또는 실패 상태를 갖습니다.

 

✅ Promise의 특징

  • 대기(pending) → 성공(fulfilled) → 실패(rejected) 의 3가지 상태를 가짐
  • .then(), .catch(), .finally()를 사용하여 결과를 처리 가능
  • 콜백 지옥(Callback Hell)을 해결하기 위한 대안

📌 Promise 예제

const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("데이터 로드 완료");
    }, 2000);
  });
};

fetchData()
  .then(data => console.log(data))
  .catch(err => console.log("에러 발생:", err));

 

이 코드는 fetchData() 함수가 2초 후 데이터를 반환하도록 만들었습니다.

.then()을 통해 성공한 경우 데이터를 받아 처리하고, .catch()를 통해 에러를 처리합니다.

 
 

2. async/await란?

async/await은 Promise를 기반으로 한 비동기 코드 처리 방식으로, 더욱 직관적이고 가독성이 좋습니다.

 

✅ async/await의 특징

  • async 함수는 항상 Promise를 반환
  • await 키워드는 Promise가 처리될 때까지 기다림
  • try...catch 문을 사용해 에러 처리가 가능

📌 async/await 예제

const fetchData = async () => {
  try {
    const result = await fetch("https://jsonplaceholder.typicode.com/todos/1");
    const data = await result.json();
    console.log(data);
  } catch (error) {
    console.log("에러 발생:", error);
  }
};

fetchData();

 

위 코드에서는 await을 사용하여 데이터를 가져오는 동안 기다리도록 만들었습니다. 이 방식은 then/catch 체이닝보다 훨씬 간결하고 가독성이 좋습니다.

 
 

3. Promise vs async/await 비교

비교 항목Promiseasync/await

비교 항목 Promise async/await
가독성 .then() 체이닝으로 다소 복잡 동기 코드처럼 간결하게 작성 가능
에러 처리 .catch() 체이닝 필요 try...catch 블록 사용
실행 방식 비동기 방식 유지 await을 사용하여 동기처럼 동작
병렬 실행 Promise.all()을 활용해야 함 Promise.all()과 함께 사용 가능

 

 

📌 Promise vs async/await 비교 예제

1) Promise 사용

fetchData()
  .then(data => console.log(data))
  .catch(error => console.log(error));

2) async/await 사용

async function getData() {
  try {
    const data = await fetchData();
    console.log(data);
  } catch (error) {
    console.log(error);
  }
}
 
 
 

4. 여러 개의 비동기 작업을 병렬로 실행하는 방법

여러 개의 비동기 작업을 동시에 실행하려면 Promise.all()을 사용하면 됩니다.

 

📌 Promise.all() 예제 (모든 요청 성공 시 결과 반환)

const fetchData1 = fetch("https://jsonplaceholder.typicode.com/todos/1").then(res => res.json());
const fetchData2 = fetch("https://jsonplaceholder.typicode.com/todos/2").then(res => res.json());

Promise.all([fetchData1, fetchData2])
  .then(results => console.log(results))
  .catch(error => console.log("에러 발생:", error));

 

Promise.all()을 사용하면 두 개의 요청을 병렬로 처리하여 속도를 최적화할 수 있습니다.

 

 

 

 

5. 언제 Promise를 사용하고 언제 async/await을 사용할까?

상황 추천 방식
간단한 비동기 처리 async/await 사용
가독성이 중요한 경우 async/await 사용
여러 개의 비동기 작업 병렬 실행 Promise.all() 사용
에러를 세밀하게 제어해야 할 경우 Promise 체이닝 활용

 

👉 결론:
단순한 비동기 처리는 async/await을 사용하고,

여러 개의 비동기 작업을 병렬로 처리할 경우 Promise.all()을 활용하는 것이 최적의 방법입니다.

 
 
 

6. 🔥면접 대비 예상 질문

Q1. Promise와 async/await의 차이점은?

답변:
Promise는 .then() 체이닝을 이용한 비동기 처리 방식이고, async/await은 await 키워드를 사용하여 동기 코드처럼 비동기 코드를 작성할 수 있습니다.

  • Promise: .then(), .catch() 체이닝 방식 → 콜백 지옥 해결
  • async/await: 동기적 코드 스타일로 가독성 향상

🔹 비교 예제

// Promise 사용
fetchData().then(data => {
  console.log(data);
}).catch(error => {
  console.log(error);
});

// async/await 사용
async function getData() {
  try {
    const data = await fetchData();
    console.log(data);
  } catch (error) {
    console.log(error);
  }
}

 

 

 

Q2. async/await 내부에서 에러 처리는 어떻게 하나요?

✅ 답변:
try...catch 블록을 사용하여 에러를 처리합니다.

 

🔹 예제

const fetchData = async () => {
  try {
    const response = await fetch("https://invalid-url.com"); // 잘못된 URL
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error("에러 발생:", error);
  }
};

fetchData();

 

try 블록에서 비동기 코드 실행 → catch 블록에서 에러 처리

 

 

Q3. async 함수는 항상 Promise를 반환하나요?

✅ 답변:
네, async 함수는 항상 Promise를 반환합니다.

  • 함수 내부에서 값이 반환되면 자동으로 Promise로 감싸짐

🔹 예제

async function returnString() {
  return "Hello";
}

returnString().then(console.log); // Promise를 반환하므로 .then() 사용 가능

 

 

 

Q4. 여러 개의 비동기 작업을 병렬로 실행하려면?

✅ 답변:
Promise.all() 또는 Promise.allSettled()을 사용하면 여러 개의 비동기 작업을 병렬 실행할 수 있습니다.

 

🔹 Promise.all() 예제 (모든 요청이 성공해야만 결과 반환)

const fetchData1 = fetch("https://jsonplaceholder.typicode.com/todos/1").then(res => res.json());
const fetchData2 = fetch("https://jsonplaceholder.typicode.com/todos/2").then(res => res.json());

Promise.all([fetchData1, fetchData2])
  .then(results => console.log(results))
  .catch(error => console.log("에러 발생:", error));

 

🔹 Promise.allSettled() 예제 (개별 요청의 성공/실패 여부를 반환)

Promise.allSettled([fetchData1, fetchData2])
  .then(results => console.log(results)); // 성공/실패 여부를 각각 확인 가능

 

 

 

Q5. Promise와 async/await 중 어느 것을 선택해야 할까요?

✅ 답변:

  • 가독성이 중요한 경우 → async/await
  • 여러 개의 비동기 작업을 병렬 처리해야 할 경우 → Promise.all()
  • 에러 처리를 세밀하게 제어해야 할 경우 → Promise의 .catch() 체이닝