이전 글에서 ES6의 변수선언 방법, 화살표 함수, Rest 파라미터, Spread / Destructuring에 대해 정리했었다. 이외에도 템플릿/강화객체 리터럴, 클래스, 모듈, 고차함수 등의 변경점이 있었지만 이 글에서는 Promise에 대해 정리해보려 한다.
Promise
Promise는 자바스크립트에서 비동기 작업을 처리하기 위해 성공 혹은 실패 상태를 나타내는 객체이다. 이전부터 라이브러리를 통해 구현되었지만, ES6에서 기본 문법으로 지원하게 되었다. new Promise()를 통해 생성하거나, Async/Await를 통해 암시적으로 Promise를 반환핟을 수 있다.
선언
const myFirstPromise = new Promise((resolve, reject) => {
// 비동기 코드 예시 setTimeout
setTimeout(function () {
resolve("성공!");
}, 250);
});
myFirstPromise.then((successMessage) => {
console.log("Good!" + successMessage); // >> Good!성공!
});
수행한 비동기 작업(위 코드에서는 setTimeout)이 성공한 경우 resolve(...)를, 실패한 경우 reject(...)를 호출한다.
상태
- 대기(Pending) : 요청이 처리 중인 상태
- 이행(Fullfilled) : 요청이 성공한 상태
- 거부(Rejected) : 요청이 실패한 상태
요청의 성공/실패 여부와 관련 없이 대기 상태를 벗어났다면 프로미스가 처리(Settled)됐다고 말하며, 이같이 프로미스가 처리됐거나, 다른 프로미스의 상태에 의해 '잠김'되었을 때의 상태를 리졸브(Resolved)되었다고 한다.
Promise Chaining
기존의 콜백함수를 통해 비동기 처리하는 방식과는 달리, Promise는 몇 가지 특징을 보장한다.
- 자바스크립트 이벤트 루프가 현재 실행중인 호출 스택을 완료하기 전까지는 절대 호출되지 않는다.
- 비동기 작업 성공 / 실패 후에 then()을 이용해 순차적인 비동기 처리가 가능하며, 이 또한 위의 특징을 보장한다.
- then()을 여러개 사용해 비동기 처리를 구현할 수 있다. 이를 Promise Chaning이라고 한다.
연속적인 비동기 처리 예시
1. 콜백함수 사용
doSomething(function (result) {
doSomethingElse(
result,
function (newResult) {
doThirdThing(
newResult,
function (finalResult) {
console.log("Got the final result: " + finalResult);
},
failureCallback,
);
},
failureCallback,
);
}, failureCallback);
2. Promise Chain
doSomething()
.then(function (result) {
return doSomethingElse(result);
})
.then(function (newResult) {
return doThirdThing(newResult);
})
.then(function (finalResult) {
console.log("Got the final result: " + finalResult);
})
.catch(failureCallback);
3. 축약 표현식 (return 값을 반드시 필요로 함)
doSomething()
.then((result) => doSomethingElse(result))
.then((newResult) => doThirdThing(newResult))
.then((finalResult) => {
console.log(`Got the final result: ${finalResult}`);
})
.catch(failureCallback);
같은 로직을 Promise를 사용해 이렇게 직관적으로 바꿀 수 있다.
에러 전파 (Error propagation)
콜백함수 사용 코드에서, 요청이 실패할 경우 failureCallback은 세 번 발생한다. 이와 달리 Promise Chain에서는 예외 발생 시 멈추고 Chain의 아래에서 catch를 찾아, 단 한 번만 발생하게 된다.
1. Promise Chain을 사용한 비동기 구현
doSomething()
.then((result) => doSomethingElse(result))
.then((newResult) => doThirdThing(newResult))
.then((finalResult) => console.log(`Got the final result: ${finalResult}`))
.catch(failureCallback);
2. 해당 로직의 동기적 모델링
try {
const result = syncDoSomething();
const newResult = syncDoSomethingElse(result);
const finalResult = syncDoThirdThing(newResult);
console.log(`Got the final result: ${finalResult}`);
} catch (error) {
failureCallback(error);
}
3. Async / Await 구문을 이용한 동기적 표현 (ECMA2017)
async function foo() {
try {
const result = await doSomething();
const newResult = await doSomethingElse(result);
const finalResult = await doThirdThing(newResult);
console.log(`Got the final result: ${finalResult}`);
} catch (error) {
failureCallback(error);
}
}
Reference