Promise는 총 3개의 상태를 갖는다. 최초로 Pending 상태에 있다가 fulfilled와 rejected 상태로 변경되고 이후 작업을 완료하거나 다른 Promise를 체이닝하여 사용할 수 있다.
Pending(대기): 실제 작업을 위한 준비 단계로 Promise 객체 생성 및 fulfilled, rejected 상황에서 호출할 handler 함수 바인딩한다.
fulfilled(이행): 동작이 성공적으로 완료된 상태이다.
rejected(거부): 동작이 실패한 상태이다.
settled(확정): pending이 아니고 fulfilled 또는 rejected 된 상태로 다음 동작 처리 가능
Promise 객체의 생성과 호출
실제 Promise 객체를 만들어보고 간단히 동작을 살펴보자.
먼저 Promise 함수는 생성자에 executor라는 함수를 파라미터로 받는데 executor는 즉시 실행되는 함수이다.
new Promise(executor)
executor는 resolver와 rejecter라는 2개의 콜백 함수를 인자로 받는데 Promise는 executor내부에서 상황에 따라 작업 성공 시 resolver를, 실패 시 rejecter를 호출하는 것을 약속한다.(확실히 호출해준다.)
Promise가 정상동작해서 호출되는 resolver는 handler에서 사용할 값 하나를 인자로 받는다. 유사하게 Promise가 실패해서 동작하는 rejecter는 실패 이유(예외 원인) 하나를 인자로 받는다. resolver와 rejecter는 비동기 작업이 완료 후 확실히 호출된다.(약속했잖아~~)
간단한 Promise 객체의 동작을 살펴보자.
const p1 = new Promise((resolve, reject) => {
const random = Math.random();
console.log(`1. p1 execute something ${random}`);
});
console.log(p1); // pending 상태
Promise 객체를 생성하면 즉시 executor에 해당하는 코드(여기에 통상 비동기 코드가 작성된다.)를 실행한다. 이때 Promise의 상태는 Pending 상태이다. (현재의 예에서는 executor에서 아직 resolve나 reject를 호출하고 있지 않다. )
then()은 promise가 resolve될 때 실행할 콜백(onfulfilled)와 reject 될 때 실행할 콜백(onrejected)를 파라미터로 받는다. 이 콜백들은 각각 하나의 파라미터를 받는데 onfulfilled는 promise가 resolve되었을 때 전달하는 값, onrejected에는 promise가 reject된 이유가 전달된다.
then()은 반환값으로 새로운 Promise를 반환하는데 이는 Promise를 chaining 해서 사용할 수 있게 한다.
finally()는 fulfilled이든, rejected든 Promise가 종료되면 언제나 호출되는 함수이다. 따라서 then(), catch()에서 공통으로 처리해야 할 일이 있다면 이 함수에서 처리하면 된다. finally()는 파라미터가 없는 onfinally 함수를 콜백으로 받으며 Promise 객체를 반환한다.
활용
이제 상황에 따라 resolver, rejecter를 호출해서 연관된 handler를 동작시켜보자.
이제 상황에 따라서 2와 3이 호출되는데 여기서 중요한 점이executor는 즉시 실행되고resolve, reject는 즉시 실행되는것이 아니라 실행될 수 있는 상황에 비동기로 실행된다는 점이다. 따라서 위 코드의 실행 결과는 1 --> 4 --> (2 또는 3) 이 된다.