지난 블로깅에서 배웠다시피 promise
객체는 아래와 같은 문법으로 만들어질 수 있다.
let promise = new Promise(function(resolve, reject) {
// executor
});
여기서 new Promise
에 전달되는 함수는 executor(실행자, 실행 함수)
라고 부른다.
executor는 new Promise
가 만들어질 때 자동으로 실행된다. executor의 인수 resolve
와 reject
는 자바스크립트에서 자체적으로 제공하는 콜백이기 때문에 개발자는 해당 부분을 신경쓰지 않고 executor 안의 코드만 작성하면 된다.
대신 executor에서는 상황에 맞게 인수로 넘겨준 콜백 중 하나를 반드시 호출해야 한다.
value
와 함께 호출error
와 함께 호출위 내용을 요약하자면,
executor는 new Promise
가 만들어질 때 자동으로 실행된다. executor에 해당하는 부분이 처리되고 나면 executor는 처리 성공 여부에 따라 resolve
나 reject
를 호출한다.
또, new Promise
생성자가 반환하는 promise
객체는 다음과 같은 내부 프로퍼티를 갖는다.
"pending"
상태였다가 resolve
가 호출되면 "fullfilled"
, reject
가 호출되면 "rejected"
로 변경된다."undefined"
이었다가 resolve(value)
가 호출되면 value
로, reject(error)
가 호출되면 error
로 변경된다.다음 예제는, 지난 블로깅에서 비슷한 예제로 promise
생성자와 간단한 executor 함수로 만든 예시이다.
let promise = new Promise(function(resolve, reject) {
// 프로미스가 만들어지면 executor 함수는 자동으로 실행된다.
// 1초 뒤에 일이 성공적으로 끝났다는 신호가 전달되면서 result는 '완료'가 된다.
setTimeout(() => resolve("완료"), 1000);
})
executor 처리가 시작된 지 1초 후, resolve("완료")
가 호출되고, 결과가 만들어진다.
이 때, promise
객체의 상태는 다음과 같이 변한다.
resolve("완료")
state: "pending" -> state: "fulfilled"
result: "undefined" -> result: "완료"
위와 같이 일이 성공적으로 처리되었을 때의 프로미스를 fulfilled promise
(약속이 이행된 프로미스) 라고 부른다.
이번에는 executor가 에러와 함께 약속한 작업을 거부하는 경우에 대해 살펴보자.
let promise = new Promise(function(resolve, reject) {
// 1초 뒤에 에러와 함께 실행이 종료되었다는 신호를 보낸다.
setTimeout(() => reject(new Error("에러 발생!")), 1000);
});
1초 후 reject(...)
가 호출되면 promise의 상태가 "rejected"
로 변한다.
reject(Error 객체)
state: "pending" -> state: "rejected"
result: "undefined" -> result: Error 객체
위 내용을 요약해보면, executor는 보통 시간이 걸리는 일을 수행하며 해당 일이 끝나면 resolve나 reject 함수를 호출하는데, 이때 프라미스 객체의 상태가 변하게 된다.
이행(resolved) 혹은 거부(rejected) 상태의 프라미스는 처리된(settled) 프라미스라고 부르고, 반대되는 프라미스로는 대기(pending) 상태의 프라미스가 있다.
executor가 처리되고 난 후 처리된 결과나 에러를 받을 함수는 .then
, .catch
메서드를 사용해 등록된다.
.then
은 프로미스에서 가장 중요한 메서드이다.
promise.then(
function(result) { /* 결과(result)를 다룬다 */ },
function(error) { /* 에러(error)를 다룬다 */ }
);
.then
의 첫번째 인수는 프로미스가 이행되었을 때 실행되며, 여기서 실행 결과를 받는다.
.then
의 두번째 인수는 프로미스가 거부되었을 때 실행되며, 에러를 받는다.
그렇다면, 성공적으로 이행된 프로미스의 예시를 한번 살펴보자.
let promise = new Promise(function(resolve, reject) {
setTimeout(() => resolve("완료!"), 1000);
});
// executor가 처리되고 난 후 then을 통해 처리된 결과나 에러를 받음
// resolve 함수는 .then의 첫번째 함수를 실행
promise.then(
result => alert(result), // 1초 후 "완료!" 출력
error => alert(error) // 실행되지 않음
);
반면, 프로미스가 거부된 경우에는 아래와 같이 두번째 함수가 실행된다.
let promise = new Promise(function(resolve, reject) {
setTimeout(() => reject(new Error("에러 발생!")), 1000);
});
// resolve 함수는 .then의 두번째 함수를 실행
promise.then(
result => alert(result), // 실행되지 않음
error => alert(error) // 1초 후 "Error: 에러 발생!"을 출력
);
프로미스가 이행되거나 거부된 경우 둘 중 프로미스가 거부되어 에러가 발생한 경우만 다루고 싶다면 .then(null, errorHandlingFunction)
과 같이 null
을 첫번째 인수로 전달하면 된다. 또한, .catch(errorHandlingFunction)
를 사용하는 것도 가능하며 .catch
는 .then
에 null
을 전달하는 것과 동일하게 작동한다.
let promise = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("에러 발생!")), 1000);
});
// executor가 처리되고 난 후 catch를 통해 에러를 받음
// .catch(f)는 promise.then(null, f)과 동일하게 작동
promise.catch(alert); // 1초 뒤 "Error: 에러 발생!" 출력