제발 프로미스나인 팬이라면 Promise 공부하세요🙏
서론
promise에 대해 자세히 알기전에 간단하게 예시를 들어서 설명을 해보겠다
당신은 딸기요거트스무디를 먹으러 메가커피에 가서 딸기요거트스무디를 주문했다 하지만 진동벨도 없고 점원이 나왔다고 말도 해주지 않는다 그래서 당신은 계속 언제 딸기요거트스무디가 나오냐고 점원한테 물어본다
이렇게 된다면 점원은 딸기요거트스무디를 만드는데 방해가 되고 또 당신은 귀찮게 계속 물어봐야 한다
하지만 진동벨이 있다면 진동벨이 울릴때까지 다른것들을 하다가 진동벨이 울리면 딸기요거트스무디를 찾아가면 되고 점원은 옆에서 계속 물어보지 않아서 빠르게 만들수 있다
여기서 나온 진동벨이 promise와 같다고 생각하면 된다
이제 promise에 대해 자세히 알아보자~
promise
promise는 es6에 추가된 문법으로 js에서 비동기 처리를 도와주는 객체이다
promise 생성
promise를 생성하는 방법은 new 키워드를 사용해서 생성하고 필수로 1개의 함수를 받는다
const promise = new Promise((resolve, reject) => {...});
인자로 들어가는 함수를 executor 라고 부르고
promise를 생성하면 자동으로 executor가 실행된다
resolve - resolve를 사용해서 promise의 상태를 Fulfilled(이행) 상태로 만들고 값을 반환하게 할 수 있다
reject - reject를 사용해서 promise의 상태를 Rejected(실패) 상태로 만들고 error를 반환하게 할 수 있다
위에서 말한 Fulfilled, Rejected는 promise의 상태인데 promise는 3가지의 상태가 존재한다
- Pending(대기) : 로직이 완료 되지 않은 상태 (executor가 실행되면 처음 상태는 무조건 pending 상태)
- Fulfilled(이행) : 코드가 성공적으로 끝나 값을 반환한 상태 (resolve 사용시 pending -> fulfilled)
- Rejected(실패) : 코드가 실패하거나 오류가 난 상태 (reject 사용시 pending -> rejected)
// pending -> fulfilled
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("성공");
}, 3000);
});
-----------
// pending -> rejected
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
reject("실패");
}, 3000);
});
promise chaining
promise에는 [변수].메서드() 처럼 사용할수있는 then, catch, finally 메서드가 존재한다
각각 용도가 다른데 한개씩 살펴보다
- then - executor에서 resolve함수를 실행해 fulfilled 상태가 됬을때 값을 받아 사용할수 있는 메서드이다
- catch - executor에서 reject함수를 실행해 rejected 상태가 됬을때 error를 받아 사용할수 있는 메서드이다
- finally - executor에서 resolve, reject함수를 사용해서 fulfilled, rejected 상태가 되는것에 상관없이 거쳐서 실행되는 메서드이다
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("성공");
}, 3000);
});
promise.then((result) => console.log(result)).finally(() => console.log("끝"));
// "성공"
// "끝"
----------
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
reject("실패");
}, 3000);
});
promise.catch((error) => console.log(error)).finally(() => console.log("끝"));
// "실패"
// "끝"
fetch, axios
fetch와 axios도 promise 기반이다
각각의 d.ts를 살펴보면 fetch와 axios 모두 promise를 반환한다
이렇게 promise를 반환하기 때문에 fetch와 axios에도 then과 catch, finally를 사용해서 promise chaining이 가능하다
Promise.all
Promise.all은 여러개의 promise를 병렬적으로 실행시키게 만들어주는 함수이다
Promise.all을 사용하지 않고 여러개의 promise를 사용하는 코드를 봐보자
console.time();
const getStrawberryInfo = () => new Promise((resolve) => setTimeout(() => resolve('딸기'), 3000));
const getYogurtInfo = () => new Promise((resolve) => setTimeout(() => resolve('요거트'), 2000));
const getSmoothieInfo = () => new Promise((resolve) => setTimeout(() => resolve('스무디'), 5000));
const strawberryInfo = await getStrawberryInfo();
const yogurtInfo = await getYogurtInfo();
const smoothieInfo = await getSmoothieInfo();
console.timeEnd(); // 10004.60205078125 ms
각각 동기적으로 info를 불러오기 때문에 모든 setTimeout의 시간이 합쳐져 10초 이상의 시간이 걸린다
하지만 Promise.all을 사용한다면 정보를 불러오는 시간을 줄일수 있다
console.time();
const getStrawberryInfo = () =>
new Promise((resolve) => setTimeout(() => resolve('딸기'), 3000));
const getYogurtInfo = () => new Promise((resolve) => setTimeout(() => resolve('요거트'), 2000));
const getSmoothieInfo = () =>
new Promise((resolve) => setTimeout(() => resolve('스무디'), 5000));
const [strawberryInfo, yogurtInfo, smoothieInfo] = await Promise.all([
getStrawberryInfo(),
getYogurtInfo(),
getSmoothieInfo(),
]);
console.timeEnd(); // 5004.871826171875 ms
Promise.all을 사용한다면 setTimeout의 최고 시간인 5초 정도 밖에 걸리지 않는다
일반 promise와 같이 promise chaining도 가능하고
단 여러 promise중 한개의 promise라도 reject가 된다면 모든 promise가 reject 된다
마무리
오늘은 promise에 대해 알아보았다
예전에 github til로 정리 한적이 있지만 그때는 대충 이런게 있다 정도로만 공부했었는데 이번 기회에 자세히 알게 되었고 여러가지 사용방법에 대해 알게 된거 같아 뿌듯한거 같다