javascript에서는 비동기 처리를 위한 하나의 패턴으로 콜백 함수를 사용한다.
이 콜백 함수 패턴은 가독성이 좋지 않고 비동기 처리 중 발생한 에러의 예외 처리가 곤란하며 여러 개의 비동기 처리 로직을 한번에 처리하는 것도 한계가 뚜렷하다.
비동기 처리를 위해 콜백 패턴을 사용하면 처리 순서를 보장하기 위해 여러 개의 콜백 함수가 중첩되어 복잡도가 높아지는 콜백 헬이 발생하는 단점도 있다.
아래는 콜백 헬이 발생하는 예.
step1(function(value1) {
step2(value1, function(value2) {
step3(value2, function(value3) {
step4(value3, function(value4) {
step5(value4, function(value5) {
// value5를 사용하는 처리
});
});
});
});
});
콜백 헬이 발생하는 이유는 비동기 처리는 실행 완료를 기다리지 않고 다음 로직을 실행하기 때문이다.
따라서 비동기 함수 내에서 처리 결과를 반환하면 기대한 대로 동작하지 않는다.
이와 같은 단점을 보완한 Promise가 ES6(ECMAScript6)에서 도입되었다.
Promise는 Promise 생성자 함수를 통해 인스턴스화 한다.
Promise 생성자 함수는 비동기 작업을 수행 할 콜백 함수를 인자로 전달 받는데 이 콜백 함수는 resolve와 reject 함수를 인자로 전달 받는다.
// Promise 객체의 생성
const promise = new Promise((resolve, reject) => {
// 비동기 작업을 수행한다.
if (/* 비동기 작업 수행 성공 */) {
resolve('result');
}
else { /* 비동기 작업 수행 실패 */
reject('failure reason');
}
});
Promise는 비동기 처리가 성공했는지 실패했는지 등의 상태 정보를 갖는다.
상태로는 pending, fulfilled, rejected, settled가 있다.
pending은 비동기 처리가 아직 수행되지 않고 resolve나 reject가 호출되지 않은 상태이다.
fulfilled는 비동기 처리가 성공(수행)하고 resolve 함수가 호출된 상태이다.
reject는 비동기 처리가 실패(수행)하고 reject 함수가 호출된 상태이다.
const promiseAjax = (method, url, payload) => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.setRequestHeader("Content-type", "application/json");
xhr.send(JSON.stringify(payload));
xhr.onreadystatechange = function() {
// 서버 응답 완료가 아니면 무시
if (xhr.readyState !== XMLHttpRequest.DONE) return;
if (xhr.status >= 200 && xhr.status < 400) {
// resolve 메소드를 호출하면서 처리 결과를 전달
resolve(xhr.response); // Success!
} else {
// reject 메소드를 호출하면서 에러 메시지를 전달
reject(new Error(xhr.status)); // Failed...
}
};
});
};
Promise 후속 처리 메서드
Promise로 구현된 비동기 함수는 Promise 객체를 반환해야 한다.
Promise로 구현된 비동기 함수를 호출하는 caller는 Promise 객체의 후속 처리 메서드를 통해 비동기 처리 결과를 전달 받아 처리한다.
Promise 객체가 가지고 있는 상태에 따라 후속 처리 메서드를 체이닝 방식으로 호출한다.(콜백 헬을 해결하는 방식.)
then
then 메서드는 두 개의 콜백 함수를 인자로 전달 받는다.
첫번째 콜백 함수는 성공했을 때 호출되고 두번째 콜백 함수는 실패했을 때 호출된다.
then 메서드는 Promise를 반환한다.
catch
예외(비동기 처리에서 발생한 에러와 then 메서드에서 발생한 에러)가 발생하면 호출된다.
catch 메서드는 Promise를 반환한다.