JavaScript

[JavaScript] 프라미스(promise) 객체

FRDYtheme 2022. 12. 28. 12:31

비동기 작업을 위한 패턴으로 이행에 성공했을 때와 실패했을 때의 동작을 미리 약속하는 것.

이 때 동작은 콜백함수로 이루어지며 성공했을 시 resolve, 실패했을 시 reject로 실행된다.

 

new Promise() 생성자 함수로 프라미스 객체를 생성하면 그와 동시에 콜백함수가 호출되는데

이 때 전달되는 함수는 executor(실행자, 실행 함수)라고 한다.

 

resolve, reject는 자바스크립트가 제공하는 자체 콜백 함수로

함수의 이행 결과에 따라 resolve 혹은 reject 중 하나의 값은 무조건 호출된다.

 

new Promise가 생성하는 promise 객체의 내부 프로퍼티.

state

  • 기본값 'pending(대기 상태)' 
  • resolve 호출 시 fulfilled(이행 상태)
  • reject 호출 시 rejected(실패 상태)

result

  • 기본값 'undefined'
  • resolve 호출 시 value 전달.
  • reject 호출 시 error 전달.

<작성 방법>

let promise = new Promise(resolve, reject)
resolve(); //성공시 불러 올 콜백함수
reject(); //실패시 불러 올 콜백함수

<resolve 예제>

<script>
  let promise = new Promise((resolve, reject) => {
    // setTimeout은 executor로 new Promise 생성 시 즉각 호출.
    setTimeout(() => resolve(`${console.log("이행합니다.")}`), 1000);
  });
  // resolve의 value인 console.log가 1초후 콘솔창에 출력.
</script>

 

<reject 예제>

<script>
  let promise = new Promise((resolve, reject) => {
    setTimeout(() => reject(new Error("에러 객체 호출")), 1000)
  });
  // reject의 error인 new Error가 1초후 콘솔창에 출력.
</script>

이렇게 promise 객체가 실행을 끝내면 처리된 promise가 되며 변경된 상태는 더 이상 변하지 않는다.

 

즉, resolve든 reject든 둘 중 하나의 상태는 무조건 호출 되며 resolve가 호출됐으면 reject로 재변경은 이루어지지 않음.

그래서 resolve가 호출이 되는 executor 이후에 작성된 reject 실행문은 무시된다.

<script>
  let promise = new Promise((resolve, reject) => {
    resolve(alert("실행되면 promise객체는 처리된 상태가 된다."));
    // executor가 즉각 실행되고 resolve로 처리된 promise 객체 상태가 된다.
    reject(new Error("한 번 처리된 promise 객체의 상태는 변하지 않는다.")); //무시
  });
</script>

위 예제에서는 처리 결과를 확인할 수 있게 alert, console.log 등으로 확인했지만

promise 객체는 처리된 상태를 지니게 됐을 뿐 어딘가에서 호출해서 사용한 상태는 아니다.

  console.log(promise)
  // Promise라는 객체를 반환할 뿐. value를 반환하지는 않는다.

상태가 처리된 promise를 사용하는 메서드는 아래와 같다.

 

then, catch, finally

then

then은 promise 객체의 가장 기본적인 메서드로 작성 순서에 따라 각 상태에 대한 executor를 인수로 받는다.

<script>
  let promise = new Promise((resolve, reject) => {
    resolve(".then의 첫 번째 줄에 매개변수로 전달된다.");
    // executor가 즉각 실행되고 resolve로 처리된 promise 객체 상태가 된다.
    reject(new Error(".then의 두 번째 줄에 매개변수로 전달된다.")); //무시
  });
  promise.then(
    (result) => alert(result), // result에 인수로 전달된 resolve의 value가 alert된다.
    (reject) => alert(reject)
  );
</script>

첫 번째 줄에 작성된 함수의 매개변수에는 resolve의 value가 인수로 전달되고,

두 번째 줄에 작성된 함수의 매개변수에는 reject의 error가 인수로 전달된다.

 

각 줄은 쉼표(,)로 구분하며 성공의 경우만 다루고 싶다면 인수를 하나만 작성하면 된다.

<script>
  let promise = new Promise((resolve, reject) => {
    resolve("성공의 경우만 생각합니다.");
  });
  promise.then((result) => alert(result)); // 성공의 경우만 생각합니다.
</script>

catch

반대로 에러의 경우만 다루고 싶다면 .then에서 첫 번째 인수에 null을 전달하면 되는데, 이는 .catch를 작성하는 것과 같다.

<script>
  let promise = new Promise((resolve, reject) => {
    reject(new Error("실패만 다룹니다."));
  });
  promise.then(null, (rejected) => {
    alert(rejected);
  });

//-------------------------------------------------

  let promise = new Promise((resolve, reject) => {
    reject(new Error("실패만 다룹니다."));
  });
  promise.catch(rejected => alert(rejected))
</script>

finally

try..catch문의 finally와 마찬가지로 promise의 처리 상태와 상관 없이 처리가 끝나면 항상 실행된다.

매개변수가 없으며 promise의 처리 상태도 확인할 수 없기 때문에 promise의 처리가 끝났는 지 등을 알리는보편적인 동작을 수행할 때 사용하기 좋다.

 

<script>
  let promise = new Promise((resolve, reject) => {
    resolve("fulfilled 상태로 처리되었습니다.");
  });
  promise
    .finally(() => {
      alert("promise가 처리되었습니다.");
    })
    .then((resolve) => alert(resolve));
</script>

 

 


 

<예제>

<body>
  <script>
    let boo = true;

    // promise 객체 생성
    // new Promise(resolve, reject);
    const coffee = new Promise((res, rej) => {
      boo ? res('커피 주문') : rej('주문 실패');
    });

    // promise 객체 사용 (promise체이닝)
    // coffee
    //   .then(good => console.log(good))
    //   .catch(bad => console.log(bad));

    coffee.then(
      good => console.log(good), // 성공 시 실행되는 함수 (첫번 째 인수)
      bad => console.log(bad) // 실패 시 실행되는 함수 (두번 째 인수)
    );
  </script>
</body>