자바스크립트에서 제공하는 비동기를 간편하게 처리할 수 있도록 도와주는 Object이다.
정상적으로 기능이 수행되었다면 성공한 메세지와 함께 처리된 결과값을 전달해주고, 문제가 발생했다면 error를 전달해준다.
상태 | 설명 |
---|---|
pending (대기) | 이행하거나 거부되지 않은 초기 상태 |
fulfilled (이행) | 연산이 성공적으로 완료 |
rejected (거부) | 연산이 실패함 |
Promise는 원하는 기능을 수행해서 해당하는 데이터를 생성하는 Producer, 원하는 데이터를 소비하는 Consumer로 나뉘어진다.
Promise를 사용할 때 인자로 executor라는 콜백함수를 전달해줘야 하는데 이 콜백함수에는 또 다른 2개의 콜백함수를 받는다.
resolve
: 기능을 정상적으로 수행해서 마지막에 최종데이터를 전달하는 콜백함수 reject
: 기능을 수행하다가 중간에 문제가 생기면 호출하게 될 콜백함수💡 Promise를 생성하는 순간 executor 함수가 바로 실행되니 유의해야한다.
const promise = new Promise((resolve, reject) => {
//doing some heavy work...
console.log("doing something...");
setTimeout(() => {
resolve('ellie'); //resolve 콜백함수 호출
//reject(new Error('no network')); //에러 발생
}, 2000);
});
Consumers는 then, catch, finally로 값을 받아올 수 있다.
promise.then((value) => { //value는 resolve 콜백함수에서 전달된 값
console.log(value); //ellie
})
.catch(error => { //체이닝
console.log(error); // Promise에서 reject를 반환하면 Error: no network가 출력된다.
})
.finally(() => { //finally는 무조건 호출된다
console.log("finally");
});
const fetchNumber = new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000); // 1초 후 1 전달
});
fetchNumber
.then(num => num * 2)
.then(num => num * 3)
.then(num => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(num - 1), 1000);
});
})
.then(num => console.log(num)); // 2초 후 5 가 출력된다.
const getHen = () =>
new Promise((resolve, reject) => {
setTimeout(() => resolve("🐓"), 1000);
});
const getEgg = hen =>
new Promise((resolve, reject) => {
setTimeout(() => resolve(`error! ${hen} => 🥚`, 1000)
});
const cook = egg =>
new Promise((resolve, reject) => {
setTimeout(() => resolve(`${egg} => 🍳`), 1000);
});
getHen()
.then(hen => getEgg(hen))
.then(egg => cook(egg))
.then(meal => console.log(meal));
🐓 => 🥚 => 🍳
💡 callback 함수를 전달할때 받아오는 value를 다른 함수 인자로(단, 인자가 한개일 때) 호출하는 경우에 생략가능
/* --- 생략 전 --- */
getHen()
.then(hen => getEgg(hen))
.then(egg => cook(egg))
.then(meal => console.log(meal));
/* --- 생략 후 --- */
getHen()
.then(getEgg) //hen을 바로 다음 함수 인자로 넘기기 때문에 생략가능
.then(cook) //egg를 바로 cook함수 인자로 넘기기 때문에 생략 가능
.then(console.log); //meal을 바로 출력하기 때문에 생략 가능
❔ 그런데 만약 네트워크 문제가 생겨서 🥚을 받아오는데 문제가 생긴다면 어떻게 해야될까?
const getHen = () =>
new Promise((resolve, reject) => {
setTimeout(() => resolve("🐓"), 1000);
});
const getEgg = hen =>
new Promise((resolve, reject) => {
setTimeout(() => reject(new Error(`error! ${hen} => 🥚`)), 1000) //reject
});
const cook = egg =>
new Promise((resolve, reject) => {
setTimeout(() => resolve(`${egg} => 🍳`), 1000);
});
getHen()
.then(getEgg)
.then(cook)
.then(console.log);
.catch(console.log);
를 추가하고 실행해보면 에러가 잘 잡힌것을 확인할 수 있다.getHen()
.then(getEgg)
.then(cook)
.then(console.log)
.catch(console.log); //catch
만약 달걀을 받아올때 무슨 문제가 생긴다면 준비한 다른 재료(🥩)로 대체를 하고 싶다면 아래와 같이 작성하면 된다.
getHen()
.then(getEgg)
.catch(error => {
return '🥩'; // 🥩 로 대체!
})
.then(cook)
.then(console.log)
.catch(console.log);
🥩 => 🍳
이전 포스팅(콜백이해하기)에서 겪었던 콜백지옥을 Promise로 수정해보자.
class UserStorage {
loginUser(id, password) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if((id === 'ellie' && password === 'dream') ||
(id === 'coder' && password === 'academy') ) {
resolve(id);
} else {
reject(new Error(new Error('not found')));
}
}, 2000);
});
}
getRoles(user) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if(user === 'ellie') {
resolve({name: 'ellie', role: 'admin'});
} else {
reject(onError(new Error('no access')));
}
}, 1000);
});
}
}
const userStorage = new UserStorage();
const id = prompt('enter your id');
const password = prompt('enter your password');
userStorage.loginUser(id, password)
.then(userStorage.getRoles)
.then((user) => {
alert(`Hello ${user.name} , you have a ${user.role}`);
})
.catch(console.log);
훨씬 깔끔해졌다..!! 😏
잘 읽고 갑니다