비동기 연산이 받아올 미래의 완료(또는 실패) 및 그 결과값을 나타냅니다.
비동기를 (콜백함수 대신에) 간편하게 처리할 수 있도록 도와주는 오브젝트이다.
Promise를 사용하면 마치 synchronous한 것처럼 값을 반환할 수 있다. 이는 미래의 어떤 시점에 최종 결과값이 아닌 Promise 자체를 반환한다.
정해진 (장시간의) 기능을 수행하고 나서 정상적으로 수행되면 성공과 함께 처리된 결과값을 전달해주고, 만약 기능 수행 중 문제가 발생했다면 에러를 전달해준다.
pending → fulfilled or rejected
: 프로세스가 heavy한 오퍼레이션을 수행하고 있는 중인지, 기능 수행이 완료되어 성공했는지, 실패했는지와 같은 상태를 나타낸다.
: 이행하거나 거부되지 않은 초기 상태
: 연산이 성공적으로 완료된 상태
: (오류가 나서) 연산이 실패한 상태
: 프로미스 안의 코드를 수행한 후 전달하고자하는 데이터를 만든다. 즉, Promise Object를 말함
🌟 Doing some heavy work ( network, read files ) !
그 이유는, heavy한 것들을 synchronous하게 처리하게 되면 뒤에 있는 코드들이 실행되지 않기 때문에 시간이 좀 걸리는 일들은 promise를 만들어 비동기적으로 처리하는 것이 좋다.
const promise=new Promise((resolve,reject)=>{
console.log('doing something...');
setTimeout(()=>{
// resolve('merry');
reject(new Error('no network'));
},2000)
});
(resolve,reject)=>{do something...}
: executor라는 콜백함수를 전달해야함
Promise를 만드는 순간 전달된 excuter라는 콜백함수가 바로 실행된다.
: 기능 정상 수행 후 마지막의 최종 데이터를 전달하는 콜백함수
: 중간에 문제 발생시 호출하게 될 콜백함수로, 보통 Error object를 통해서 값(new Error(~))을 전달함
then, catch, finally 를 통해 값을 받아올 수 있음
promise
.then(value => console.log(value))
.catch(error => console.log(error))
.finally(() => console.log('finally'));
// 'value=>console.log(value)'는 'console.log'로 줄여서 표현가능함
: resolve에서 전달된 값을 인자로 받아옴 → 성공시 어떻게 처리할 건지 콜백함수 등록
.catch
나 .then
을 써서 chaining 할 수 있음.then
은 값을 바로 전달해줘도 되지만 다른 새로운 Promise를 만들어 전달해줄수도 있음.then(num=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>resolve(num-1),1000);
})
})
.then(num=>console.log(num));
: reject에서 전달된 값을 인자로 받아옴 → 에러 발생시 어떻게 처리할 건지를 다룸
: 성공 여부에 상관없이 마지막에 호출되어지는 함수
보통 한두 개 이상의 비동기 작업이 순차적으로 실행되어야 하는 경우가 흔하다. 이전 단계의 비동기 작업이 성공하고 나서 그 결과값을 이용해 다음 비동기 작업을 실행하게 된다. 이럴때 사용하면 좋은 것이 promise chaining이다.
다만, promise도 과하게 nesting할 경우 callback hell과 비슷해지므로 주의해야한다.
const fetchNumber=new Promise((resolve, reject)=>{
setTimeout(()=>resolve(1),1000);
});
console.log(fetchNumber);
Promise를 생성하면 바로 executor가 실행되고 성공 여부에 따라 상태와 결과값이 Promise로 반환된다.
[console]
Promise {<fulfilled>: 1}
__proto__: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: 1
만약 resolve나 reject가 등록되지 않으면 상태는 "pending"이며 결과값은 undefined
이게 된다.
Promise Chaining에 대해선 아래 예제을 읽어보자!
const fetchNumber=new Promise((resolve, reject)=>{
setTimeout(()=>resolve(1),1000);
});
fetchNumber
.then(num=>num*2) //num에는 resolve에서 전달받은 1이 들어가게 되고 성공적으로 연산이 완료되면 .then에 결과값을 전달하게 됨
.then(num=>num*3)//반복...
.then(num=>{
return new Promise((resolve,reject)=>{
setTimeout(() => resolve(num-1),1000);
}); //❗then은 값을 바로 전달할 수도, promise를 전달할 수도 있음
})
.then(num=>console.log(num));
[console]
5
chain에서 작업이 실패하더라도 catch를 통해 처리가 가능하다.
아래는 비동기적으로 암탉과 계란, 계란후라이를 얻어와 console에 출력하는 예제이다.
const getHen=()=>
new Promise((resolve,reject)=>{
setTimeout(()=>resolve('🐔'),1000);
});
const getEgg=hen=>
new Promise((resolve,reject)=>{
setTimeout(() =>resolve(`${hen}=> 🥚`),1000);
//setTimeout(() =>reject(new Error(`error! ${hen}=>🥚`)),1000);
});
const cook=egg=>
new Promise((resolve,reject)=>{
setTimeout(()=>resolve(`${egg}=>🍳`),1000);
});
getHen()
.then(getEgg)
.then(cook)
.then(console.log)
[console]
🐔=>🥚=>🍳
에러가 생겼을 경우엔 어떻게 처리하는지 살펴보자!
const getHen=()=>
new Promise((resolve,reject)=>{
setTimeout(()=>resolve('🐔'),1000);
});
const getEgg=hen=>
new Promise((resolve,reject)=>{
setTimeout(()=>reject(new Error(`error! ${hen}=>🥚`)),1000);
});
const cook=egg=>
new Promise((resolve,reject)=>{
setTimeout(()=>resolve(`${egg}=>🍳`),1000);
});
getHen()
.then(getEgg)
.catch(error=>'🍞')
.then(cook)
.then(console.log);
[console]
🍞=>🍳
❗ 참고자료
https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Using_promises
https://www.youtube.com/channel/UC_4u-bXaba7yrRz_6x6kb_w