프로미스 Promise

sohyun·2022년 7월 25일
0

드림코딩 강의 정리

목록 보기
19/20

프로미스란?

  • ES6에서 비동기 처리르 위한 또 다른 패턴으로
    전통적인 콜백패턴이 가진 담점을 보완하며 비동기 처리 시점을 명확하게 표현할 수 있는 장점을 가지고 있다.

콜백 패턴의 단점 - 콜백 헬

동기식 처리 모델 Synchronous processing model

  • 동기식 처리모델은 직렬적으로 태스크를 수행한다.
  • 서버에서 데이터를 가져와 태스크를 수행할 때 데이터가 응답될 때까지 이후의 태스크는 블로킹 된다.

비동기식 처리 모델 Asynchronous processing model

  • 비동기식은 병렬적으로 태스크를 수행한다.
  • 종료되지 않은 상태라 하더라도 대기하지 않고 다음 태스크 수행
  • 자바스크립트의 대부분의 DOM이벤트와 Timer함수, Ajax요청은 비동기식 동작이다.

단 콜백헬이 발생하는 단점이 있다

  • 여러개의 콜백함수가 중첩되어 복잡도가 높아지는 것을 말한다.
  • 가독성을 나쁘게 하며 실수를 유발한다.

예를 들어

<!DOCTYPE html>
<html>
<body>
  <script>
    // 비동기 함수
    function get(url) {
      // XMLHttpRequest 객체 생성
      const xhr = new XMLHttpRequest();

      // 서버 응답 시 호출될 이벤트 핸들러
      xhr.onreadystatechange = function () {
        // 서버 응답 완료가 아니면 무시
        if (xhr.readyState !== XMLHttpRequest.DONE) return;

        if (xhr.status === 200) { // 정상 응답
          console.log(xhr.response);
          // 비동기 함수의 결과에 대한 처리는 반환할 수 없다.
          return xhr.response; // ①
        } else { // 비정상 응답
          console.log('Error: ' + xhr.status);
        }
      };

      // 비동기 방식으로 Request 오픈
      xhr.open('GET', url);
      // Request 전송
      xhr.send();
    }

    // 비동기 함수 내의 readystatechange 이벤트 핸들러에서 처리 결과를 반환(①)하면 순서가 보장되지 않는다.
    const res = get('http://jsonplaceholder.typicode.com/posts/1');
    console.log(res); // ② undefined
  </script>
</body>
</html>
  • 비동기 함수 내의 readystatechange 이벤트 핸들러에서 처리 결과를 반환( 1 ) 하면 순서가 보장되지 않는다.
  • 즉, ( 2 ) 에서 get함수가 반환한 값을 참조할 수 없다.
  • 비동기 함수의 처리 결과를 반환하는 경우,
    순서가 보장되지 않기 때문에 그 반환 결과를 가지고 후속 처리를 할 수 없다.
  • 즉, 비동기 함수의 처리 결고가에 대한 처리는 비동기 함수의 콜백 함수 내에서 처리해야하는데 이때 콜백 헬이 발생한다.

에러 처리의 한계

  • 가장 심각한 것은 에러 처리가 곤란하다.
  • setTimeout 함수의 콜백함수 내에서 발생시킨 에러는 catch 블록에서 캐치되지 않아 프로세스는 종료된다.

프로미스의 생성

  • new Promise() Promise 생성자 함수를 통해 인스턴스화 한다.
  • resolve,reject함수 를 콜백함수를 인자로 받는다
// Promise 객체의 생성
const promise = new Promise((resolve, reject) => {
  // 비동기 작업을 수행한다.

  if (/* 비동기 작업 수행 성공 */) {
    resolve('result');
  }
  else { /* 비동기 작업 수행 실패 */
    reject('failure reason');
  }
});
  • Promise는 비동기 처리의 성공(fulfilled),실패(rejected)하였는지 등의 상태(state) 정보를 갖는다
  • 비동기 처리 성공 : resolve 호출 --> fulfilled 상태
  • 비동기 처리 실패 : reject 호출 --> rejected 상태
상태의미구현
pending비동기 처리가 아직 수행되지 않은 상태resolve 또는 reject함수가 아직 호출되지 않은 상태
fulfilled비동기 처리가 수행된 상태(성공)resolve함수가 호출된 상태
rejected비동기 처리가 수행된 상태(실패)reject함수가 호출된 상태
settled비동기 처리가 수행된 상태(성공 또는 실패)resolve 또는 reject함수가 호출된 상태

프로미스의 후속 처리 메서드

  • Promise로 구현된 비동기 함수는 Promise객체를 반환해야 한다.
  • Promise 객체는 상태를 갖는데 이 상태에 따라 후속처리 메서드를 체이닝 방식으로 호출한다.
  • 메서드 체이닝이란?
    : 메서드가 객체를 반환하게 되면 메서드의 반환 값인 객체를 통해 또 다른 함수를 호출할 수 있다.
    함수1().함수2().함수3()...
    - then() : 두 개의 콜백함수를 인자로 전달받는다.
    성공 시(fulfilled,resolve함수 호출된 상태) 호출,
    실패 시 (rejected,reject 함수 호출된 상태) 호출
    - catch() : 예외 발생시 호출
    : 비동기 처리에서 발생된 에러, then()에서 발생한 에러

프로미스의 에러 처리

  • 에러처리는 then()의 두번째 콜백함수에서 전달하지 않는 것이 좋다.
  • catch()를 사용하여 가독성을 높이는 것이 좋다.
 get()
   .then((json) => {
            //resolve가 호출됨에 따라 실행
            console.log(json);
        })
   .catch((e)=> {
            //reject가 호출됨에 따라 실행
            console.log(e);
        });

프로미스의 정적 메소드

Promise.all

Promise.all([new Promise(),new Promise(),new Promise()...)

  • Promise가 담겨있는 배열등의 이터러블을 인자로 전달받음
  • 모든 프로미스 처리가 성공하면 각각의 프로미스가 resolve한 처리 결과를 배열에 담아 resolve하는 새로운 프로미스를 반환한다.
  • 이 때 첫번째 프로미스가 가장 나중에 처리되어도 Promise.all()의 반환하는 프로미스는 첫번째 프로미스가 resolve한 처리 결과부터 차례대로 배열에 담아 배열을 resolve하는 새로운 프로미스를 반환한다
  • 즉 처리 순서가 보장된다
  • 프로미스 처리가 하나라도 실패하면 가장 먼저 실패한 프로미스가 reject한 에러를 새로운 프로미스를 즉시 반환한다.

Promise.race

  • 프로미스가 담겨 있는 배열 등의 이터러블을 인자로 전달받음
  • Promise.all 메서드 처럼 모든 프로미스를 병렬처리하는 것이 아닌
    가장 먼저 처리된 프로미스가 resolve한 처리결과를 resolve하는 새로운 프로미스를 반환한다.
  • 에러가 발생한 경우는 Promise.all 메소드와 동일하게 처리된다.
  • 즉, Promise.race 메소드에 전달된 프로미스 처리가 하나라도 실패하면 가장 먼저 실패한 프로미스가 reject한 에러를 reject하는 새로운 프로미스를 즉시 반환한다.
function getBanana() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve('🍌');
    }, 1000);
  });
}

function getApple() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve('🍎');
    }, 3000);
  });
}

function getOrange() {
  return Promise.reject(new Error('no orange'));
}


//static함수를 이용하여 좀 더 간편하게 사용가능
// Promise.all 병렬적으로 한번에 모든 Promise들을 실행!
Promise.all([getBanana(), getApple()]) //
  .then((fruits) => console.log('all', fruits));

// Promise.race 주어진 Promise중에 제일 빨리 수행된것이 이김!
Promise.race([getBanana(), getApple()]) //
  .then((fruit) => console.log('race', fruit));

REF

promiseweb

profile
냠소현 개발일지

0개의 댓글