[JavaScript] Promise와 Async/Await

2025. 2. 7. 19:00·Frondend/JavaScript

Intro

...잠깐 봤는데도 이해가 안되네 resolve 에 도달하면 then이고 reject 도달하면 catch? 개발자 의도나 실수로 둘 다 도달하지 않으면 일단 코드는 정상적으로 동작한거니 then으로 가나?.... 어지럽네 진짜

Promise

MDN Promise 문서에 따르면 아래와 같이 나와있다.

Promise 객체는 비동기 작업이 맞이할 미래의 완료 또는 실패와 그 결과 값을 나타냅니다.
Promise는 프로미스가 생성된 시점에는 알려지지 않았을 수도 있는 값을 위한 대리자로, 비동기 연산이 종료된 이후에 결과 값과 실패 사유를 처리하기 위한 처리기를 연결할 수 있습니다. 프로미스를 사용하면 비동기 메서드에서 마치 동기 메서드처럼 값을 반환할 수 있습니다. 다만 최종 결과를 반환하는 것이 아니고, 미래의 어떤 시점에 결과를 제공하겠다는 '프로미스(promise)'를 반환합니다.

쉽게 설명하면 비동기 작업을 진행하고 처리 결과를 reslove()와 reject() 함수를 사용해서 fulfilled 또는 rejected 로 상태로 반환하는 객체이다.

특징

  • 최초의 상태(Pending)에서 상태가 변경되면 다시 변경되지 않는다.
  • Fulfilled 또는 Rejected 상태에서 resolve() 와 reject()함수를 만나면 무시한다.
  • resove() 또는 reject() 함수를 만나도 바로 반환하는게 아니라 그 이후에 있는 코드들도 정상적으로 실행이된다.
  • 한번 실행된 Promise 객체는 다시 실행시켜도 내부 로직이 동작하지 않는다. => 함수로 감싸서 실행하면 재실행 가능
  • 체이닝을 이용하여 여러 비동기 작업을 순차적으로 실행 가능

3가지 상태(states)

  • Pending(대기) : Promise 실행 시 초기 상태이며, 아직 성공이나 실패가 되지 않은 상태, new Promise()
  • Fulfilled(이행) : 작업이 완료되어 결과를 반환한 상태, resolve()
  • Rejected(실패) : 비동기 작업이 실패하거나 오류가 발생한 상태, reject()

MDN - Promise 처리 흐름

Promise 기본 문법 및 예제

기본 문법

const <Promise 객체> = new Promise((resolve, reject) => {
  resolve(); // Promise 성공
  // OR
  reject(); // Promise 실패
});

<Promise 객체>.then(<콜백 함수>); // fulfilled 상태
// 또는
<Promise 객체>.catch(<콜백 함수>); // rejected 상태

사용 예제

const myPromise = new Promise((resolve, reject) => {
  const num = Math.random();
  
  if (num > 0.5) {
    resolve("성공 : " + num);
  } else {
    reject("실패 : " + num);
  }
});

myPromise
  .then((success) => console.log("then : ", success))
  .catch((error) => console.log("catch : ", error))
  .finally(() => console.log("finally 실행");

후속 처리 메소드

.then()

  • 최대 2개까지 인자(콜백 함수)를 받을 수 있다.(onFulfilled, onRejected)
  • 첫 번째 인자는 Promise 코드에서 resolve()가 호출되어 fulfilled 상태일때 실행
  • 두 번째 인자는 Promise 코드에서 reject()가 호출되거나 에러 또는 예외처리가 발생하여 rejected 상태일때 실행
  • 기본적으로 반환되는 값은 Promise 객체(상태 : fulfilled)
  • 내부 코드 실행 도중에 예외가 발생하면 rejected 상태로 변경

.catch()

  • reject()가 호출되거나 에러 또는 예외처리가 발생하는 등 Promise 상태가 rejected 상태일 때 실행
  • 기본적으로 반환되는 값은 Promise 객체(상태 : fulfilled)

.finally()

  • Promise의 상태가 fulfilled인지 rejected인지 상관 없이 항상 실행
  • 예외가 발생하지 않는 한 받은 Promise 상태를 그대로 반환
  • 반환되는 값은 Promise 객체

결론적으로, Promise Chaining이 가능하도록 .then(), .catch(), .finally()는 항상 새로운 Promise를 반환합니다!

정적 메서드

.all()

  • 인자로 배열에 여러개의 Promise 객체를 담아서 한번에 반환 받는다.
  • 하나라도 거부되면 즉시 전체가 거부 됩니다.
Promise.all([Promise 객체 1, Promise 객체 2, Promise 객체 3, ...])
  .then((results) => {
    console.log("전부 성공");
    
    results.forEach((result, num) => {
      console.log(`${num}번쨰 Promise 결과 : ${result}`);
    })
  .catch(() => console.log("하나 이상 실패");

.allSettled()

  • .all()과 달리 거 rejected 되는 것이 있더라도 모든 Promise가 완료될 때까지 기다린다. 
Promise.allSettled([Promise 객체 1, Promise 객체 2, Promise 객체 3, ...])
  .then((results) => {
    console.log("모든 Promise가 완료됨");
    
    results.forEach((result, num) => {
      if(result.status == 'fulfilled') {
        console.log(`${num}번째 Promise 상태: ${result.status}, 결과: ${result.value}`);
      } else if (result.status == 'rejected') {
        console.log(`${num}번째 Promise 상태: ${result.status}, 이유: ${result.reason}`);
      }
    });
  });

.race()

  • 입력 받은 여러 개의 Promise 객체들중 가장 먼저 완료된 결과만 반환
const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('promise1'), 100);
});
const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('promise2'), 200);
});
const promise3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('promise2'), 200);
});

Promise.race([promise1, promise2, Promise3])
  .then((result) => console.log(`가장 빨리 완료한 Promise는 ${result}`));

.resolve() 와 .reject()

  • 들어오는 입력값을 fulfilled, rejected 상태인 Promise 객체로 감싸서 반환
const resolvePromise = Promise.resolve(value) // 상태가 Fulfilled인 Promise 객체 반환
resolvePromise
  .then((result) => console.log(result)) // 출력 : value
  
const rejectPromise = Promise.reject(value) // 상태가 Rejected인 Promise 객체 반환
rejectPromise
  .catch((error) => console.log(error)) // 출력 : value

Async/Await

Promise 의 단점을 보완하여 좀 더 간결하고 직관적으로 작성할 수 있도록 ES8부터 나온 기능으로 비동기 코드를 동기처럼 작성할 수 있다.

말그대로 Async 비동기 라는 뜻으로 함수 앞에 붙어서 비동기 함수라는걸 뜻하고, Await 기다리다 라는 뜻으로 Promise 함수가 결과값을 반환하기 전까지 그 이후 코드들을 진행시키지 않고 기다린다.

  • Async : 비동기로 동작시키고 싶은 함수 앞에 위치하며, Promise 객체를 반환한다.
  • Await : Async 함수 내에서 만 사용할 수 있으며, Promise를 반환하는 함수 앞에 붙여서 동작한다. (Promise가 아니라도 붙일수는 있지만 기대대로 동작하지 않음)

기본 문법

async function 함수명() {
  await 비동기_메서드();
}

 기존 Promise vs Async/Await

// 기존 Promise 문법
function fetchData(url) {
  return fetch(url)
    .then((result) => {
      console.log("코드 동장 성공 : ", result);
    })
    .catch((error) => {
      console.error("에러 발생 : ", error);
    });
}

// Async/Await 사용 코드
async function fetchData(url) {
  try {
    const result = await fetch(url);
    console.log("코드 동작 성공 : ", result);
  } catch (error) {
    console.error("에러 발생 : ", error);
  }
}

 

병렬처리

1. 기본적인 방식

async function fetchData() {
  console.log("데이터 요청 시작");

  const response1 = await promise1;
  console.log(response1);

  const response2 = await promise2;
  console.log(response2);
}

// 내가 생각했을 때 조금 더 좋은 방법
async function fetchData() {
  const response1 = promise1;
  const response2 = promise2;
  
  const data1 = await response1;
  const data2 = await response2;
  
  console.log(response1);
  console.log(response2);
}

2. Promise.all 활용 (로직은 조금 차이나지만 allSettled도 가능)

async function fetchData() {
  const [response1, response2] = await Promise.all([promise1, promise2]);
  
  console.log(response1);
  console.log(response2);
}

마무리

Promise 길어도 오전이면 얼추 다 찾아보겟지 라는 생각을 가지고 시작했는데, 오전은 커녕 하루종일 찾아보면 찾아볼수록 계속 먼가가 나온다... 나 자바도 이렇게 까지 파본적 있던가? 이쯤되니 난중에 자바 공부 다시 시작해서 하나하나 뜯어보면 또 몰랐던 먼가가 나올거 같네...

그래도 Async/Await은 동작은 비동기이지만 동기 코드 처럼 보여서 가독성이라던가 try-catch 등으로 예외처리가 편해진거 같다.

 

[참고]

MDN - Promise 문서

반응형

'Frondend > JavaScript' 카테고리의 다른 글

[JavaScript] 프로토타입(Prototype) 과 클래스(Class)  (0) 2025.02.12
[JavaScript] Fetch API  (1) 2025.02.09
[JavaScript] 비동기와 타이머 (w. Event Loop)  (0) 2025.02.06
[JavaScript] 호이스팅(Hoisting)  (0) 2025.02.06
[JavaScript] this 알아보자  (1) 2025.02.05
'Frondend/JavaScript' 카테고리의 다른 글
  • [JavaScript] 프로토타입(Prototype) 과 클래스(Class)
  • [JavaScript] Fetch API
  • [JavaScript] 비동기와 타이머 (w. Event Loop)
  • [JavaScript] 호이스팅(Hoisting)
JJuuuunn
JJuuuunn
  • JJuuuunn
    JJuuuunn
    JJuuuunn
  • 전체
    오늘
    어제
    • 분류 전체보기 (70)
      • Backend (7)
        • Java (7)
      • Frondend (48)
        • Vue.js (12)
        • JavaScript (21)
        • Css (1)
      • Infra (0)
      • Git (2)
      • CS (5)
        • DataBase (0)
        • Network (2)
        • OS (0)
        • Algorithm (0)
      • 리뷰 (5)
        • 강의 (1)
        • Books (4)
      • ETC (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    VUE
    자바스크립트
    KDT
    혼공컴운
    객체
    이벤트
    자바
    신세계i&c
    HTML
    Java
    axios
    API
    렌더링
    Network
    Vue.js
    javascript
    frontend
    혼자 공부하는 컴퓨터구조+운영체제
    Watch
    깊은 감시
  • 최근 댓글

  • 최근 글

  • 반응형
  • hELLO· Designed By정상우.v4.10.1
JJuuuunn
[JavaScript] Promise와 Async/Await
상단으로

티스토리툴바