Promise의 3가지 상태 (states)
- Pending(대기) - 비동기 처리 로직이 아직 완료되지 않은 상태
- Fullfilled(이행) - 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태
- Rejected(실패) - 비동기 처리가 실패하거나 오류가 발생한 상태
대기(Pending) 중인 promise는 값과 함께 이행할 수도, 어떤 이유(error)로 인해 거부 될 수도 있다. 이런 경우, promise의 then 메서드에 의해 대기열(큐)에 연결된 관련 이벤트가 호출된다. 해당 핸들러가 연결될 때 promise가 이미 이행됬거나 거부된 경우, 핸들러가 호출되므로 비동기 작업 완료와 연결 중인 핸들러 사이에 경합 조건은 없다.
Promise.prototype.then() 및 Promise.prototype.catch() 메서드의 반환 값은 새로운 Promise이므로 서로 연결할 수 있다.
💡 Javascript에서 Promise는 콜백 함수를 연결할 수 있는, 이미 진행 중인 프로세스를 나타낸다. 💡 promise가 pending(대기)에서 벗어나 이행 또는 거부된다면 promise가 settled(처리)됐다고 말한다. resolve는 promise가 처리됐거나, 다른 promise 상태에 맞춰 상태가 '잠김'됐다는 의미로 쓰인다. |
Pending(대기)
new Promise() 메서드 호출 시 대기(pending) 상태가 되며, 호출할 때 콜백 함수를 선언할 수 있고 콜백 함수의 인자는 resolve, reject이다.
Fullfilled(이행)
콜백 함수의 인자 resolve를 실행하면 이행(Fullfilled) 상태가 되며, 이행 상태가 되면 then()을 이용하여 처리 결과 값을 받을 수 있다.
function getData() {
return new Promise(function(resolve, reject) {
var data = 100;
resolve(data);
});
}
// resolve()의 결과 값 data를 resolvedData로 받음
getData().then(function(resolvedData) {
console.log(resolvedData); // 100
});
Rejected(실패)
콜백 함수의 인자 reject를 실행하면 실패(Rejected) 상태가 되며, 실패 상태가 되면 실패한 이유(실패 처리의 결과 값)를 catch()로 받을 수 있음.
function getData() {
return new Promise(function(resolve, reject) {
reject(new Error('Request is failed');
});
}
// reject()의 결과 값 Error를 err에 받음
getData().then().catch(function(err) {
console.log(err); // Error : Request is failed
});
생성자 구문.
new Promise(executor)
executor - resolve 및 reject 인수를 전달할 실행함수. (실행 함수는 Promise 생성자가 생성한 객체를 반환하기도 전에 호출된다)
실행함수는 보통 어떤 비동기 작업을 시작한 후 모든 작업을 끝내면 resolve를 호출해 프로미스를 이행하고, 오류가 발생한 경우, reject를 호출해 거부한다. 실행 함수에서 오류를 던지면 promise는 거부되고 실행 함수의 반환값은 무시된다.
예제.
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('foo');
}, 300);
});
promise1.then((value) => {
console.log(value); // expected output: "foo"
});
console.log(promise1); // expected output: [object promise]
인스턴스 메서드.
Promise.prototype.catch()
promise가 reject 시 콜백을 추가하고, 콜백이 호출된 경우, 그 반환값으로 이행하며 호출되지 않을 경우, 즉 이전 promise가 이행하는 경우 이행한 값을 그대로 사용해 이행하는 새로운 promise를 반환한다.
const p1 = new Promise((resolve, reject) => {
resolve('Success!');
});
p1.then((value) => {
console.log(value); // "Success!"
throw new Error('Error Message!');
}).catch((e) => {
console.log(e.message); // "Error Message!"
}).then(() => {
console.log('after a catch the chain is restored');
}, function () {
console.log('Not fired do to the catch');
})
Promise.prototype.then()
promise에 resolve와 reject 콜백을 추가하고, 콜백이 호출될 경우, 그 반환값으로 이행하며 호출되지 않을 경우(onFullfilled, onRejected 중 상태에 맞는 콜백이 함수가 아닐 경우) 처리된 값과 상태 그대로 처리되는 새로운 promise를 반환한다.
Promise.prototype.finally()
promise의 이행과 거부 여부에 상관없이 처리될 경우 항상 호출되는 처리기 콜백을 추가하고, 이행한 값 그대로 이행하는 새로운 promise를 반환한다.
예제.
function getData() {
return new Promise(function(resolve, reject) {
$.get('url', function(response) {
if(response) {
resolve(response);
}
reject(new Error('Request is failed'));
});
});
}
// 위 $.get() 호출 결과에 따라 'response' 또는 'Error' 출력
getData().then(function(data) {
console.log(data); // reponse 값 출력
}).catch(function(err) {
console.log(err); // Error 출력
});
서버에서 제대로 응답을 받아오면 resolve() 메서드를 호출하고, 응답이 없으면 reject() 메서드를 호출하는 예제임.
호출된 메서드에 따라 then()이나 catch()로 분기하여 응답 결과 또는 오류를 출력.
프로미스 체이닝(Promise Chaining)
** then() - 해당 Promise가 성공했을 때의 동작을 지정함. 인자로 함수를 받음.
** catch() - 해당 Promise가 실패했을 때의 동작을 지정함. 인자로 함수를 받음.
위의 메서드를 활용하여 체인형태로 활용하여 Promise를 연결해서 사용할 수 있음.
function getData() {
return new Promise({
// ...
});
}
// then() 으로 여러 개의 프로미스를 연결
getData()
.then(function(data) {
//...
})
.then(function() {
//...
})
.then(function() {
//...
});
예시 1)
new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(1);
}, 2000);
})
.then(function(result) {
console.log(result); // 1
return result + 10;
})
.then(function(result) {
console.log(result); // 11
return result + 20;
})
.then(function(result) {
console.log(result); // 31
});
1. resolve()가 호출되면 Promise가 대기 상태에서 이행상태로 넘어가기 때문에 첫번째 .then() 로직으로 넘어감
2. 첫번째 .then()에서 이행된 결과 값 1을 받아 출력 후 10을 더해 다음 .then()에게 넘겨줌
3. 두번째 .then()에서도 마찬가지로 이전 Promise의 이행된 결과 값 11을 받아서 출력 후 20을 더하고 다음 .then()에서 넘겨줌
4. 마지막 .then()에서 최종 결과값 31을 출력
실제 사례 - 사용자 로그인 인증 로직
페이지에 입력된 사용자 정보를 받아와 파싱, 인증 등의 작업을 거치는 코드를 나타냄.
여기서 userInfo는 사용자 정보가 담긴 객체를 의미하고, parseValue, auth, display는 각각 Promise를 반환해주는 함수라고 가정
var userInfo = {
id: 'test@abc.com',
pw: '****'
};
function parseValue() {
return new Promise({
//...
});
}
function auth() {
return new Promise({
//...
});
}
function display() {
return new Promise({
//...
});
}
getData(userInfo)
.then(parseValue)
.then(auth)
.then(display);
Promise의 에러 처리 방법
Promise의 reject() 메서드가 호출되어 실패 상태가 될 경우, 아래와 같이 처리 가능합니다.
1. then()의 두번째 인자로 에러를 처리하는 방법
getData().then(
handleSuccess,
handleError
);
2. catch()를 이용하는 방법
gatData().then().catch();
예시)
function getData() {
return new Promise((resolve, reject) => {
reject('failed');
});
}
// 1. then()의 두번째 인자로 에러를 처리하는 코드
getData().then(function() {
//...
}, function(err) {
console.log(err);
});
// 2. catch()로 에러를 처리하는 코드
getData().then().catch(function(err)
console.log(err);
});
** Promise의 에러 처리는 가급적 catch()를 사용하길 바라며, 더 많은 예외처리 상황을 위해 Promise의 끝에 가급적 catch()를 붙이기 바람.
// then()의 두번째 인자로는 감지하지 못하는 오류
function getData() {
return new Promise((resolve, reject) => {
resolve('hi');
});
}
getData().then(function(result) {
console.log(result);
throw new Error('Error in then()'); // Uncaught (in promise) Error: Error in then()
}, function(err) {
console.log('then error:', err);
});
getData()함수의 Promise에서 resolve() 메서드를 호출하여 정상적으로 로직을 처리했지만, then()의 첫번째 콜백 함수 내부에서 오류가 나는 경우, 오류를 제대로 잡아낼 없음. 따라서 코드를 실행하면 주석처리된 것과 같은 오류가 남.(에러 로그로 확임)
똑같은 오류를 catch()로 처리 시 다른 결과가 나옴.
// catch()로 오류를 감지하는 코드
function getData() {
return new Promise((resolve, reject) {
resolve('hi');
});
}
getData().then(function(result) {
console.log(result); // hi
throw new Error('Error in then()');
}).catch(function(err) {
console.log('then error: ', err); // then error : Error: Error in then()
});
주석처리 된것 같은 발생한 에러를 콘솔에서 확인할 수 있음.
'javascript' 카테고리의 다른 글
REST API(Representational State Transfer) (0) | 2022.08.02 |
---|---|
표준 빌트인 객체(standard built-in objects/native objects/global objects) (0) | 2022.07.28 |
Part 1. Promise란? (작동 방식) (0) | 2022.07.14 |
[ES6] Spread Operator(...) (0) | 2022.07.12 |
배열의 중복 제거 (0) | 2022.06.23 |