JavaScript | 프로미스

yuni·2022년 11월 22일
0

javascript

목록 보기
15/16
post-thumbnail

📌 프로미스(Promise)?

⇨ 프로미스(Promise)는 자바스크립트 비동기 처리에 사용되는 객체이다.(ES6도입) 프로미스는 전통적인 콜백 패턴이 가진 단점을 보완하며 비동기 처리 시점을 명확하게 표현할 수 있다는 장점이 있다.

👉 프로미스의 필요성?

자바스크립트는 비동기 처리를 위한 하나의 패턴으로 콜백 함수를 사용한다. 하지만 전통적인 콜백 패턴은 콜백 헬로 인해 가독성이 나쁘고 비동기 처리 중 발생한 에러의 처리가 곤란하며 여러 개의 비동기 처리를 한번에 처리하는 데도 한계가 있다.

✅ 프로미스 생성

→ 프로미스는 Promise 생성자 함수를 통해 인스턴스화한다. Promise 생성자 함수는 비동기 작업을 수행할 콜백 함수를 인자로 전달받는데 이 콜백 함수는 resolve와 reject 함수를 인자로 전달받는다.

// Promise 객체의 생성
const promise = new Promise((resolve, reject) => {
  // 비동기 작업을 수행한다.

  if (/* 비동기 작업 수행 성공 */) {
    resolve('result');
  }
  else { /* 비동기 작업 수행 실패 */
    reject('failure reason');
  }
});

Promise는 비동기 처리가 성공(fulfilled)하였는지 또는 실패(rejected)하였는지 등의 상태(state) 정보를 갖는다. ‖

상태의미구현
pending(대기)비동기 처리가 아직 수행되지 않은 상태resolve 또는 reject 함수가 아직 호출되지 않은 상태
fulfilled(이행)비동기 처리가 수행된 상태 (성공)resolve 함수가 호출된 상태
rejected(실패)비동기 처리가 수행된 상태 (실패)reject 함수가 호출된 상태
settled(처리)비동기 처리가 수행된 상태 (성공 또는 실패)resolve 또는 reject 함수가 호출된 상태

✅ 프로미스의 후속 처리 메소드

Promise로 구현된 비동기 함수는 Promise 객체를 반환하여야 한다. Promise로 구현된 비동기 함수를 호출하는 측(promise consumer)에서는 Promise 객체의 후속 처리 메소드(then, catch, finally)를 통해 비동기 처리 결과 또는 에러 메시지를 전달받아 처리한다.

  • then
    then 메소드는 두 개의 콜백 함수를 인자로 전달 받는다. 첫 번째 콜백 함수는 성공(fulfilled, resolve 함수가 호출된 상태) 시 호출되고 두 번째 함수는 실패(rejected, reject 함수가 호출된 상태) 시 호출된다.
    then 메소드는 Promise를 반환한다.
  • catch
    예외(비동기 처리에서 발생한 에러와 then 메소드에서 발생한 에러)가 발생하면 호출된다. (에러를 처리한다.)
    catch 메소드는 Promise를 반환한다.
  • finally
    무슨 결과를 호출 받든 최종적으로 무조건 호출된다.

✅ 프로미스의 에러 처리

비동기 처리 시에 발생한 에러는 두가지의 방법이 있는데,

  1. then 메서드의 두 번째 콜백 함수로 처리할 수 있다.
    ⇒ 단, then 메서드의 두 번째 콜백 함수는 첫 번째 콜백 함수에서 발생한 에러를 캐치하지 못하고 코드가 복잡해져서 가독성이 좋지 않다.
  2. Promise 객체의 후속 처리 메서드 catch를 사용해서 처리할 수도 있다.
    모든 then 메서드를 호출한 이후에 호출하면 비동기 처리에서 발생한 에러(reject 함수가 호출된 상태)뿐만 아니라 then 메서드 내부에서 발생한 에러까지 모두 캐치할 수 있다.

따라서, 더 많은 예외 처리 상황을 위해 catch 메서드를 사용하는 것을 권장한다.

✅ 프로미스 체이닝(Promise Chaining)

이전 단계 비동기 작업이 성공하고 나서 그 결과값을 이용하여 다음 비동기 작업을 실행해야 하는 경우, 함수의 호출이 중첩(nesting)이 되어 복잡도가 높아지는 콜백 헬이 발생한다. 이를 후속 처리 메소드를 체이닝(Chaining)하여 여러개의 프로미스로 해결 할 수 있다.

function getData() {
  return new Promise({
    // ...
  });
}

// then() 으로 여러 개의 프로미스를 연결한 형식
getData()
  .then(function(data) {
    // ...
  })
  .then(function() {
    // ...
  })
  .then(function() {
    // ...
  });

then 메소드가 Promise 객체를 반환하도록 하면 여러 개의 프로미스를 연결하여 사용할 수 있다.

👉 프로미스의 정적 메소드

Promise는 주로 생성자 함수로 사용되지만 함수도 객체이므로 메소드를 갖을 수 있다. Promise 객체는 4가지 정적 메소드를 제공한다.

Promise.resolve / Promise.reject

존재하는 값을 Promise로 래핑하기 위해 사용

  • promise.resolve : resolve하는 프로미스를 생성
  • promise.reject : reject하는 프로미스를 생성
//resolve
function nums1(first) {
  return Promise.resolve(`${first} => 1`);
}
function nums2(second) {
  return Promise.resolve(`${second} => 2`);
}
//reject
function Numresult() {
  return Promise.reject(new Error('숫자를 전달 할 수 없음'));
}

Numresult()
  .catch(() => '0')
  .then(nums1)
  .then(nums2)
  .then(console.log);
// 0 => 1 => 2 

Promise.all - 병렬처리

프로미스가 담겨 있는 배열 등의 이터러블을 인자로 전달 받는다. 그리고 전달받은 모든 프로미스를 병렬로 처리하고 그 처리 결과를 resolve하는 새로운 프로미스를 반환한다.

Promise.all([
  new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
  new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
  new Promise(resolve => setTimeout(() => resolve(3), 1000))  // 3
]).then(console.log) // [ 1, 2, 3 ]
  .catch(console.log);
  • Promise.all 메소드는 전달받은 모든 프로미스를 병렬로 처리한다. 모든 프로미스의 처리가 종료될 때까지 기다린 후 아래와 모든 처리 결과를 resolve 또는 reject한다.

  • 모든 프로미스의 처리가 성공하면 각각의 프로미스가 resolve한 처리 결과를 배열에 담아 resolve하는 새로운 프로미스를 반환한다. 이때 첫번째 프로미스가 가장 나중에 처리되어도 Promise.all 메소드가 반환하는 프로미스는 첫번째 프로미스가 resolve한 처리 결과부터 차례대로 배열에 담아 그 배열을 resolve하는 새로운 프로미스를 반환한다. 처리 순서가 보장된다.

  • 프로미스의 처리가 하나라도 실패하면 가장 먼저 실패한 프로미스가 reject한 에러를 reject하는 새로운 프로미스를 즉시 반환한다.

Promise.race - 가장 먼저 처리된 프로미스

가장 먼저 처리된 프로미스가 resolve한 처리 결과를 resolve하는 새로운 프로미스를 반환한다.

Promise.race([
  new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
  new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
  new Promise(resolve => setTimeout(() => resolve(3), 1000))  // 3
]).then(console.log) // 3
  .catch(console.log);

Promise.allSettled - 모든 결과 호출

Promise.all은 모두 성공됐을때 호출이 된다. 중간에 실패한 경우가 있을때(하나라도 에러가 있을경우)는 이행처리가 취소되기때문에 호출이 되지 않는다.

Promise.allSettled를 이용한다면 모든 Promise가 성공되지 않아도 된다. 성공하던 실패하던 그 결과를 무조건 배열에 결과값을 담아준다.

성공했을 땐 status 가 'fulfilled', 실패했을 땐 'rejected'

참고 및 출처
promise - MDN
프로미스 - PoiemaWeb
자바스크립트 Promise 쉽게 이해하기 - joshua1988
Promise.allSettled() - MDN

profile
˗ˋˏϟˎˊ˗ 개발 지식 쌓기

0개의 댓글