TIL - 5회차
2021.03.06
- Promise
Promise
Promise 란?
프로미스란 자바스크립트 비동기 처리에 사용되는 객체이다.
Promise를 사용하여 비동기 작업이 (성공 혹은 실패로) 완료된 후의 결과를 받을 수 있다.
JS 비동기 처리 : 특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드를 먼저 수행하는 자바스크립트의 특성을 의미한다.
let promise = new Promise(function(resolve, reject) {
//실행 코드
});
promise 객체는 new
키워드로 생성합니다. new Promise
에 전달되는 함수는 executor(실행자, 실행 함수)라 한다.
executor는 new Promise
가 만들어질 때 자동으로 실행되는데, 결과를 최종적으로 만들어내는 제작 코드를 포함한다.
executor의 인수 resolve와 reject는 자바스크립트가 자체적으로 제공하는 콜백이다.
- resolve(value) - 일이 성공적으로 끝난 경우, 그 결과를 나타내는
value
와 함께 호출- reject(error) - 에러 발생 시 에러 객체를 나타내는
error
와 함께 호출- 대신 executor에선 결과를 즉시 얻든, 늦게 얻든 상관없이 인수로 받은 콜백 중 하나의 콜백은 반드시 호출해야 한다.
프로미스의 상태(States)
프로미스는 총 4개의 상태를 갖는다.
상태란 프로미스의 처리 과정을 의미한다. new Promise()
객체로 프로미스를 생성하고 종료될 때까지 3가지 상태(pending, fulfilled, rejected)를 갖는다.
상태 | 의미 | 구현 |
---|---|---|
pending(대기) | 비동기 처리가 아직 수행되지 않은 상태 | resolve 또는 reject 함수가 아직 호출되지 않은 상태 |
fulfilled(성공) | 비동기 처리가 수행된 상태 | resolve 함수가 호출된 상태 |
rejected(실패) | 비동기 처리가 수행된 상태 | reject 함수가 호출된 상태 |
settled(성공 또는 실패) | 비동기 처리가 수행된 상태 | resolve 또는 reject 함수가 호출된 상태 |
- 한번
Setteld
(처리)된 값은 재실행 할 수 없다.
state
—> 처음엔"pending"(대기)
이었다 resolve가 호출되면"fulfilled"
, reject가 호출되면"rejected"
로 변합니다.result
—> 처음엔undefined
이었다, resolve(value)가 호출되면value
로, reject(error)가 호출되면error
로 변합니다.
Pending(대기)
new Promise()
메서드를 호출하면 대기 상태가 된다.
new Promise();
Fulfilled(성공)
resolve
를 실행하면 성공 상태가 된다.
new Promise(function(resolve, reject) {
resolve();
});
Rejected(실패)
reject
를 호출하면 실패 상태가 된다.
new Promise(function(resolve, reject) {
reject();
});
- 프로미스 흐름도 - 출처 : MDN
사용
.then
, .catch
, .finally
메서드를 이용해 응답에 따라 분기 처리 하여 Promise 응답 결과를 사용한다.
resolve시 then으로
.then
은 프라미스에서 가장 중요하고 기본이 되는 메서드이다.
let promise = new Promise(function(resolve, reject) {
//실행 코드
});
promise.then(
function(result) { /* 결과(result)를 다룹니다 */ },
function(error) { /* 에러(error)를 다룹니다 */ }
);
//예시
let promise = new Promise(function(resolve, reject) {
setTimeout(() => resolve("done!"), 1000);
});
// resolve 함수는 .then의 첫 번째 함수(인수)를 실행합니다.
promise.then(
result => alert(result), // 1초 후 "done!"을 출력
error => alert(error) // 실행되지 않음
);
작업이 성공적으로 처리된 경우만 다룰 경우 .then
에 인수를 하나만 전달한다.
let promise = new Promise(resolve => {
setTimeout(() => resolve("done!"), 1000);
});
promise.then(alert); // 1초 뒤 "done!" 출력
reject시 catch로
에러가 발생한(실패한) 경우만 다루고 싶다면 .catch
를 사용한다.
.then(null, errorHandlingFunction)
같이null
을 첫 번째 인수로 전달해도 된다..catch
는.then
에null
을 전달하는 것과 동일하게 작동한다.
//예시
let promise = new Promise(function(resolve, reject) {
setTimeout(() => reject(new Error("에러 발생!")), 1000);
});
// reject 함수는 .then의 두 번째 함수를 실행합니다.
promise.then(
result => alert(result), // 실행되지 않음
error => alert(error) // 1초 후 "Error: 에러 발생!"를 출력
);
//catch
let promise = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("에러 발생!")), 1000);
});
// .catch(f)는 promise.then(null, f)과 동일하게 작동합니다
promise.catch(alert); // 1초 뒤 "Error: 에러 발생!" 출력
finally
프라미스가 처리되면(성공 또는 실패) 콜백함수가 항상 실행된다는 점에서 .finally(f)
호출은 .then(f,f)
와 유사하다.
결과가 어떻든 응답이 필요하면 finally
가 유용하다.
new Promise((resolve, reject) => {
/* 비동기 처리를 수행하고, 그 후 resolve·reject를 호출함 */
})
// 성공·실패 여부와 상관없이 프라미스가 처리되면 실행됨
.finally(() => 로딩 인디케이터 중지)
.then(result => result와 err 보여줌 => error 보여줌)
여기서 중요한 점은
.then
메소드는 다시Promise
를 반환한다.Promise
객체를 반환한다는 것은.then
,.catch
메소드를 사용할 수 있다는 것을 뜻하며, 이를 통해 연속적으로.then
메소드를 사용하여Promise chaining
이 가능하다는 것을 의미한다.(.catch
메소드 이후에도 chaining이 가능)
여러 개의 프로미스 연결 (Promise chaining)
function getData() {
return new Promise({
// ...
});
}
// then() 으로 여러 개의 프로미스를 연결한 형식
getData()
.then(function(data) {
// ...
})
.then(function() {
// ...
})
.then(function() {
// ...
});
//예시
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000); // (*)
}).then(function(result) { // (**)
alert(result); // 1
return result * 2;
}).then(function(result) { // (***)
alert(result); // 2
return result * 2;
}).then(function(result) {
alert(result); // 4
return result * 2;
});
위 코드는 프로미스 객체를 하나 생성하고 setTimeout()을 이용해 1초 후에 resolve()를 호출하는 예제이다.
Promise.all
Promise.all()
메서드는 순회 가능한 객체에 주어진 모든 프로미스가 이행한 후, 혹은 프로미스가 주어지지 않았을 때 이행하는 Promise를 반환합니다. 주어진 프로미스 중 하나가 거부하는 경우, 첫 번째로 거절한 프로미스의 이유를 사용해 자신도 거부합니다.
Promise.all
은Promise
인스턴스들이 담긴 배열을 인자로 받아 사용하는데,
배열의 모든 요소가Promise
인스턴스일 필요는 없다.
const promise1 = Promise.resolve(3);
const promise2 = 42; // 프로미스가 아닌 값
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
//배열을 인자로 받음
Promise.all([promise1, promise2, promise3]).then(values => {
console.log(values); // Array [3, 42, 'foo']
});
// resolve되는 값들을 destructuring 할 수 있다.
Promise.all([promise1, promise2, promise3]).then(([one, two, three]) => {
console.log(one); // 3
console.log(two); // 42
console.log(three); // 'foo'
});
//다른 예시
const emptyPromiseAll = Promise.all([]); // 빈 배열을 동기적 실행
const promiseA = Promise.all([1337, "hi"]); // 프로미스가 아닌 값은 무시하지만 비동기적으로 실행됨
const promiseB = Promise.all([1, 2, 3, Promise.resolve(444)]); // 위와 동일
p; // [] 동기적 실행히라 then 메소드 사용하지 않아도 된다.
p2.then(res => console.log(res)); // [1337, 'hi']
p3.then(res => console.log(res)); // [1, 2, 3, 444]
Promise 실무사례 예시
getData(userInfo)
.then(parseValue)
.then(auth)
.then(diaplay);
//userInfo(사용자 정보)를 받아와 파싱, 인증, 등의 작업을 수행하는 코드
var userInfo = {
id: '[email protected]',
pw: '****'
};
function parseValue() {
return new Promise({
// ...
});
}
function auth() {
return new Promise({
// ...
});
}
function display() {
return new Promise({
// ...
});
}
//parseValue, auth, display는 각각 프로미스를 반환해주는 함수라고 가정
프로미스 에러 처리 방법
위에서 언급한 것 처럼 2가지 방식이 있다.
1. .then(null, errorHandlingFunction)
와 같이 .then
의 두 번째 인자로 에러 처리
2. .catch
를 이용한 에러 처리
가급적 catch()를 사용하여 에러를 처리하는 게 더 효율적이다.
// then()의 두 번째 인자로는 감지하지 못하는 오류 function getData() { return new Promise(function(resolve, reject) { resolve('hi'); }); } getData().then(function(result) { console.log(result);//hi throw new Error("Error in then()"); // Uncaught (in promise) Error: Error in then() }, function(err) { console.log('then error : ', err); });
resolve()
메서드를 호출하여 정상적으로 처리했지만,.then
의 첫 번째 인자 내부에서 발생한 오류는 제대로 잡아내지 못한다.
Uncaught (in promise) Error: Error in then()
에러를 잡지 못했다는 에러가 발생한다.
하지만.catch
로 처리하면 다른 결과가 나온다.// catch()로 오류를 감지하는 코드 function getData() { return new Promise(function(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() });
더 많은 예외 처리 상황을 위해 catch()를 통해 에러를 처리 하자
Author And Source
이 문제에 관하여(TIL - 5회차), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@wdh008/TIL-5회차저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)