javaScript Promise란? all, allSettled, race
2022년 10월 03일
Promise란?
프로미스란 간단하게 비동기를 동기적으로 처리할 때 콜백함수 형태로 사용하는데 중첩해서
사용하게 될 경우에는 콜백 지옥이 탄생하게 됩니다.
loadScript("/my/script.js", function () {
loadScript("/my/script.js", function () {
loadScript("/my/script.js", function () {
loadScript("/my/script.js", function () {
loadScript("/my/script.js", function () {});
});
});
});
});
이러한 콜백 지옥에서 프로그래머가 더 코드를 읽는데 수월하게 하기 위해서 만들어진 객체입니다.
프로미스의 state(상태)
프로미스는 영어단어 그대로 약속이라는 뜻입니다. 약속을 수행하기 위해서는 4가지의 상태가 존재합니다.
-
pending: 아직 약속을 수행 중인 상태(fulfilled, reject가 되기 전) -
fulfilled: 약속이 지켜진 상태 -
rejected: 약속이 파투 난 상태입니다. -
settled: 약속이 지켜지든 파투 나든 일단 결론이 난 상태입니다.
프로미스는 선언과 실행 두 부분으로 나눌 수가 있습니다.
코드로보는 Promise
프로미스 선언
//Promise 선언
let 프로미스 = function (param) {
return new Promise(function (resolve, reject) {
// 비동기를 표현하기 위해 setTimeout 함수를 사용
window.setTimeout(function () {
// 파라메터가 참이면,
if (param) {
resolve("해결 완료");
}
// 파라메터가 거짓이면,
else {
reject(Error("실패!!"));
}
}, 3000);
});
};
프로미스에는 js에서 제공해주는 2가지의 매개변수가 있는데 resolve, reject가 있습니다.
둘 중 하나가 먼저 실행이 되면 나머지 하나는 무시가 됩니다.
-
resolve : 완료가 된 상태로 실행 부에서 then 안에 들어갑니다.
-
reject : 실패한 상태로 실행 부에서 catch에서 수행됩니다
Promise가 생성된 직후부터 resolve, reject가 호출되기 전까지를 pending 상태라고 합니다.
프로미스 실행
//Promise 실행
프로미스(true)
.then((text) => {
console.log(text);
})
.catch((errorText) => {
console.log(errorText);
});
실행하는 곳은 매우 쉽습니다. 만약 선언 부에서 resolve가 실행되면 그 안의 매개변수를
then에서 받을 수가 있습니다.
하지만 반대로 reject가 실행되면 catch가 실행이 됩니다.
그렇다면 resolve, reject 둘 다 수행이 되든 말든 수행해야 할 동작이 있다면 어떻게 해야 할까요?
그러한 상태를 settled 라고 하는데 이때는 finally API를 사용할 수 있습니다.
//Promise finally 실행
프로미스(true)
.then((text) => {
console.log(text);
})
.catch((errorText) => {
console.log(errorText);
})
.finally(() => {
console.log("end");
});
Promise 고급 활용
프로미스를 더 고급지게 사용해보시고 싶으신 분들에게 적당한 3개의 고급기술이 있습니다.
-
Promise.all()
-
Promise.allSettled()
-
Promise.race()
Promise.all()
Promise.all() 는 인자로 배열을 받습니다. resolve된 value들의 배열을 가진 Promise를 리턴하죠
만약에 인자로 받은 Promise중 하나라도 reject가 된다면, 동작을 중지하며 reject를 리턴합니다.
const trueOrFalse = (param) => {
return new Promise((resolve, reject) => {
window.setTimeout(function () {
// 파라메터가 참이면,
if (param) {
resolve("해결 완료");
}
// 파라메터가 거짓이면,
else {
reject(Error("실패!!"));
}
}, 3000);
});
};
async function promiseAll() {
await Promise.all([trueOrFalse(true), trueOrFalse(false), trueOrFalse(true)]);
}
promiseAll().catch((err) => console.log(err));
이러한 형태로 하나라도 잘못되면 다른 resolve들을 수행하지 않게 하기위해 사용됩니다.
Promise.allSettled()
Promise.all의 동작과 유사합니다. 다만 reject된 promise가 있더라도 전체를 모두 처리해서 배열에 담아줍니다.
배열 안의 요소들은 각기 status와 value 또는 reason 프로퍼티를 가진 객체입니다.
const pr1 = Promise.resolve(1);
const pr2 = Promise.reject("rejected");
Promise.allSettled([pr1, pr2]).then(console.log);
/*
[
{ status: 'fulfilled', value: 1 },
{ status: 'rejected', reason: 'rejected' }
]
*/
Promise.race()
인자로 Promise의 배열을 받습니다. 그 중 가장 먼저 resolve되거나 reject된 promise를 반환합니다.
const pr1 = new Promise((resolve) => setTimeout(() => resolve(1), 1000));
const pr2 = new Promise((resolve) => setTimeout(() => resolve(2), 50));
Promise.race([pr1, pr2]).then(console.log);
Promise 단점
//Promise 체이닝
프로미스(true)
.then((text) => {
console.log(text);
})
.catch((errorText) => {
console.log(errorText);
})
.then((text) => {
console.log(text);
})
.catch((errorText) => {
console.log(errorText);
})
.then((text) => {
console.log(text);
})
.catch((errorText) => {
console.log(errorText);
})
.finally(() => {
console.log("end");
});
이런식으로 then, catch를 많이 사용하는것을 프로미스 체이닝이라고 합니다.
코드의 순서를 보기에는 좋지만 이것이 너무 많이 반복이 되면 프로그래머는 지치기 마련입니다.
따라서 resolve가 되었을 때 실행될 로직들을 모아두고 싶다, reject가 되었을 때 실행될 로직들을
또 따로 모아두싶으면 async, await, try, catch 문을 사용하면 됩니다.