프로미스(Promise)

SeongMok Hong·2023년 5월 3일
0

프로미스(Promise)의 등장 배경

ES6 이전에는 비동기 처리를 위해 callback 을 사용하였습니다. 함수 인자로 전달된 callback function 을 비동기 작업(서버에 대한 요청)이 끝난 후 실행하는 방식으로 문제를 해결하였습니다.

다만, 콜백 함수 방식의 가장 큰 문제점은 여러개의 비동기 요청을 중첩하여 호출하게 되면, 깊이가 계속해서 깊어지는 문제점이 생깁니다. 이러한 현상을 콜백 지옥(Callback hell) 이라 부릅니다.

중첩된 콜백 함수는 가독성이 많이 떨어지고, 유지보수를 어렵게 합니다. 이러한 문제점을 해결하고, 비동기 처리를 좀 더 편리하게 하기 위해 ES6에서는 Promise를 도입하였습니다.

Promise

Promise 객체는 비동기 작업의 최종 완료 또는 실패를 나타내는 객체입니다. 프로미스가 생성된 시점에는 처리되지 않은 값을 위한 대리자로, 비동기 작업이 종료된 이후 결과 값을 처리하기 위한 함수를 연결할 수 있습니다.

비동기 api 요청을 위한 fetch() , axios.get() 함수 등의 return type도 Promise 객체입니다.

Promise는 다음과 같은 세개의 상태 중 하나의 상태를 가집니다.

  • pending(대기) : 초기 상태.
  • fulfilled(이행) : 작업이 성공적으로 완료됨.
  • rejected(거부) : 작업이 실패함.

Promise 생성자

Promise 객체는 Promise 생성자를 활용하여 만들 수 있습니다.

new Promise((resolve, reject) => {
	// executor
 	// 비동기 작업 코드
})

Promise 생성자는 executor(실행 함수) 를 인자로 받습니다. 실행함수는 비동기 작업을 하고, 작업의 성공 및 실패여부에 따라 resolve 또는 reject 를 호출합니다.

  • resolve(value) : 비동기 작업이 성공한 경우 호출합니다. Promise의 상태를 fulfilled 로 변경합니다. 인자로 결과값을 넘겨줍니다.
  • reject(reason) : 비동기 작업이 실패한 경우 호출합니다. Promise의 상태를 rejected 로 변경합니다. 인자로 오류의 원인(주로 Error 객체)을 넘겨줍니다.

아래 예제는 Promise를 생성하는 예시입니다.

myPromise 는 숫자 두개를 입력받아 나눗셈을 하는 Promise 객체를 반환하는 함수입니다. 조건 분기를 통해 나누려는 숫자가 0이 아닌 경우에는 작업이 성공해야 하므로 resolve 를 호출하였고, 나누려는 숫자가 0인 경우는 작업이 실패해야 하므로 reject 를 호출했습니다.

function myPromise(num1, num2) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (num2 !== 0) {
        resolve(num1 / num2);    // fulfilled
      } else {
        reject(new Error('0으로 나눌 수 없습니다!'));    // rejected
      }
    }, 1000);
  });
}

Promise 작업 이후 결과 처리

Promise의 비동기 작업이 마친 후 메소드를 통해 성공, 실패에 따라 처리할 수 있습니다. 사용 가능한 메소드는 다음과 같습니다.

  • Promise.prototype.then() : Promise 이행, 거부 handler callback을 추가합니다.
    // 이행 handler 추가
    somePromise.then(function(value) {
      // 이행
    });
    // 이행, 거부 handler 추가
    somePromise.then(function(value) {
      // 이행
    }, function(reason) {
      // 거부
    });
  • Promise.prototype.catch() : Promise 거부 handler callback을 추가합니다.
    somePromise.catch(function (reason) {
      // 거부
    });
  • Promise.prototype.finally() : Promise 의 성공, 실패 여부에 관련 없이 항상 호출되는 handler callback을 추가합니다.
    somePromise.finally(function () {
      // settled
      // 성공, 실패 여부에 관련 없이 항상 실행
    });

해당 메소드들은 Promise 객체를 반환합니다. Chaining을 통해 성공, 실패 관련 handler를 여러개 처리할 수 있습니다.

function myPromise(num1, num2) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (num2 !== 0) {
        resolve(num1 / num2);
      } else {
        reject(new Error('0으로 나눌 수 없습니다!'));
      }
    }, 1000);
  });
}

myPromise(1, 2)
  .then((value) => console.log(`결과값은 ${value} 입니다.`))
  .catch((error) => {
    console.log('에러 발생');
    console.log(error);
  })
  .finally(() => {
    console.log('연산 끝!');
  });
profile
안녕하세요. 홍성목입니다.

0개의 댓글