-
오늘은 어제에 이어서 Promise의 메서드에 대해서 공부해 보려고 한다.
그 이유는 MDN에서 나는 주로 공부를 하는데,
알고보니 프로미스에도 다양한 메서드가 있는것이다
물론 이걸 다 외울 순 없겠지만 이해는 하고 있으면 좋을거 같아서 정리해보려고 한다.
Promise.all()
- 순회 가능한(배열과 같은) 프로미스를 받아서 하나의 프로미스로 리턴한다.
- 리턴 값은 1️⃣ 모든 프로미스가 fulfilled 했을 때 fulfilled 값을 리턴하고,
혹은 2️⃣ 하나의 값이라도 rejected 되었으면 첫번 째 reject값을 반환한다.
- 해당 메서드는 프로미스의 결과를 집계할 때 유용하다.
예시 )
- 예시를 어떤거를 해볼까라고 생각했는데 갑자기 취업 면접이 생각났다 여튼 중간에 탈락하면 바로 끝이니 ㅠ
function doJobInterview(interviewStep) { return new Promise((resolve, reject) => { const interviewScore = Math.floor(Math.random() * 100); const isPassed = interviewScore > 40; if (isPassed) { resolve(`축하드립니다, ${interviewStep}을 합격하셨습니다! 자세한 내용은 홈페이지를 참고해주세요.`); } else { reject( `당사의 사원모집에 관련한 면접에 참석하여 주심을 감사 드립니다. 귀하의 인상적인 경력 및 면접에도 불구하고 예상보다 많은 지원자들로 인해 ${interviewStep}을 합격하지 못하였음을 통보 드립니다. 아쉽지만 귀하의 면접 참석에 대해 다시 한번 감사 드리며 앞으로의 귀하의 취업에 좋은 결과 있기를 기원하겠습니다.` ) } }); } Promise .all(['과제면접', '직무면접', '임원면접'].map(doJobInterview)) .then(message => console.log(message)) .catch(message => console.error(message));
- 모두 fulfilled 시 모든 값의 fulfilled 값 리턴
- 하나라도 틀리면 틀린 첫번째 값 리턴
- 나름 현실감 있게 만들어보았다
Promise.allSettled()
- 성공 여부 보다는 여러 비동기 작업을 수행해야 하거나, 항상 각 프로미스의 실행 결과를 알고 싶을 때 사용
- 반환 값은 프로미스에 대한 결과 값을 나타내는 객체 배열을 리턴.
function getAnonymouseFeedback(drink) { return new Promise((resolve, reject) => { const score = Math.floor(Math.random() * 100); const passedScore = score > 60; const evaluation = passedScore ? '맛있어요' : '맛없어요'; const evaluationTemplate = `음료 점수 : ${score}점 / 평가 : ${evaluation}` if (passedScore) { resolve(evaluationTemplate); } else { reject(evaluationTemplate) } }); } Promise .allSettled(['아메리카노', '카페라떼', '초코라떼'].map(getAnonymouseFeedback)) .then(message => console.log(message))
- 반환된 객체에서 status를 확인할 수 있고, fulfilled시 value를 볼 수 있으며, rejected되면 reason을 볼 수 있다.
- 이를 통해, 각각의 프로미스들이 성공했는지 실패했는지 확인할 수 있다. 그리고 이렇게 나눌 수도 있다!
function getAnonymouseFeedback(drink) { return new Promise((resolve, reject) => { const score = Math.floor(Math.random() * 100); const passedScore = score > 60; const evaluation = passedScore ? '⭐⭐⭐⭐⭐' : '⭐⭐'; const evaluationTemplate = `음료 점수 : ${score}점 / 평가 : ${evaluation}` if (passedScore) { resolve(evaluationTemplate); } else { reject(evaluationTemplate) } }); } Promise .allSettled(['아메리카노', '카페라떼', '초코라떼'].map(getAnonymouseFeedback)) .then(results => { return { good: results.filter(result => result.status === 'fulfilled'), bad: results.filter(result => result.status === 'rejected') } }) .then(results => { console.log('~ 피드백 리스트 ~') results.good.forEach(goodFeedback => console.log(`정말 대단한 바리스타군요! 🥰 from Kim / ${goodFeedback.value}`)) results.bad.forEach(badFeedback => console.log(`죄송하지만, 음료 만드는 재능은 없으신거 같습니다 😥 from Kim / ${badFeedback.reason}`)) })
Promise.any()
- 어떤 값 하나라도 성공 시, 첫번 째 fulfilled 값을 반환
- 만약에 모두 실패 시, 모든 rejected 값을 반환
- 사실 요거는 언제 사용하면 좋을까? 라는 생각이 들었는데, MDN에서 유용한 예시가 있어서 가지고 왔다.
바로 첫번째 이미지를 로드하는 함수이다.
async function fetchAndDecode(url, description) { const res = await fetch(url); if (!res.ok) { throw new Error(`HTTP error! status: ${res.status}`); } const data = await res.blob(); return [data, description]; } const coffee = fetchAndDecode("coffee.jpg", "Coffee"); const tea = fetchAndDecode("tea.jpg", "Tea"); Promise.any([coffee, tea]) .then(([blob, description]) => { const objectURL = URL.createObjectURL(blob); const image = document.createElement("img"); image.src = objectURL; image.alt = description; document.body.appendChild(image); }) .catch((e) => { console.error(e); });
- 둘 중 아무나 먼저 fetching되면 해당 이미지가 보이는 것
- 즉, 해당 메서드는 어떤 값이 먼저 오든 하나라도 성공하는 것이 목적이라면 사용하는게 좋은거 같다. 왜냐면 첫번째
fulfilled 값을 반환하기 때문에 다음 값을 기다리진 않기 때문이다.
- 만약에 모든 값이 실패하고 reject 값을 반환하면 AggregateError를 반환한다.
❓ AggregateError
- 에러를 나타내는 객체이며 여러 에러를 하나의 에러로 묶을 때 사용한다.
- 저렇게 나오고 AggregateError는 4개의 속성을 가지고 있다.
- AggregateError.prototype.message → ' All Promises rejected'
- AggregateError.prototype.name → 'AggregateError'
- AggregateError.prototype.cause → undefined
- AggregateError.prototype.errors → [ Error: "some error" ]
Promise.race()
- 메서드의 이름처럼 레이스 후 가장 처음으로 리턴되는 값을 반환한다.
- 이 값은 성공 일수도 , 실패일 수도 있으며 then()과 catch()를 통해 프로미스의 값이 반환된다.
function race(name, ms) { return new Promise((resolve) => { const seconds = ms / 1000; setTimeout(function () { resolve(`1등은 바로 ${name}님! 100m 달리기 결과 : ${seconds}초`) }, ms) }) } Promise.race([race('토끼', 5000), race('거북이', 10000)]).then(value => console.log(value)); // 1등은 바로 토끼님! 100m 달리기 결과 : 5초
- 실무에서는 이런 방식으로도 사용할 수 있겠다 ( MDN 참고 )
const data = Promise.race([ fetch("/api"), new Promise((resolve, reject) => { // Reject after 5 seconds setTimeout(() => reject(new Error("Request timed out")), 5000); }), ]) .then((res) => res.json()) .catch((err) => displayError(err));
- api를 5초동안 기다려주고 그뒤에는 바로 reject 날려서 더이상 기다리지 않도록 하는 것. 물론 뭔가 실제로 쓰지는 못할거 같지만?
오늘은 간단하게 Promise의 메서드들을 살펴보았다.
생각보다 엄청 많아서 당황... 사실 뭔가 나는 큰 틀만 공부하고 넘어간 부분이 꽤 많아서 그랬는지는
몰라도 새로운 메서드들을 많이 배웠다. 이거를 실무에서는 어떻게 사용하는지 알아보는게 좋을거 같다.
참고자료
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError
'TIL > FrontEnd' 카테고리의 다른 글
230222 TIL : React Query 배운 내용 (0) 2023.02.23 230220 TIL: RTK Query 공부내용 (0) 2023.02.20 230214 TIL : 비동기 프로그래밍 (Promise) (0) 2023.02.15 230213 TIL : 비동기 프로그래밍 (call stack, task queue, event loop) (0) 2023.02.14 Husky + lint-staged 사용하기 (0) 2023.02.13 댓글