[JS] 2개의 API 결과값 합치기

JJeong·2022년 9월 23일
0

최종 코드는 맨 밑에 '덧2' 참고!

배경

조건에 따라 api를 각각 따로 호출하고, 결과값은 합쳐서 state에 저장해야 하는 상황이다. 간단한 문제일 줄 알았는데 .then() 안에 있는 결과값을 어떻게 밖으로 빼고 가공해야 몰라서 한참 헤맸다.

if (조건문1) {
  fetch
    .get('uri')
    .then((res1) => res1)  // type : arr
    .catch(() => {})
}

if (조건문2) {
  fetch
    .get('uri')
    .then((res2) => res2)  // type : arr
    .catch(() => {})
}

// 원하는 결과값
setResult([...res1, ...res2]) // 대충 느낌만 반영한 코드

해결 방법

  1. 조건문보다 상위 스코프에 변수를 2개 생성하고, fetch에서 반환되는 값을 각각 변수에 저장해준다.
  2. 해당 변수들(promise)을 넣은 리스트를 Promise.all() 함수를 통해 single promise로 만들고, 이를 .then()으로 받으면 2차원 array로 쓸 수 있게 된다.
  3. [].concat.apply([], exampleArr) 함수를 사용해서 1차원 배열로 만든다!
let aPromise;
let bPromise;
   if (조건문1) {
      aPromise = fetch
                  .get('uri')
                  .then((res1) => res1)
                  .catch(() => {})
   }
   if (조건문2) {
       bPromise = fetch
                   .get('uri')
                   .then((res2) => res2)
                   .catch(() => {});
   }
// .filter() :api 반환값이 null일 경우, promise가 undefined이기 때문에 걸러주어야 한다
return [aPromise, bPromise].filter((promise) => promise); 
})
  .then((promises) => {
     Promise.all(promises)
       .then((twoDimenArr) => {
              setResult([].concat.apply([], twoDimenArr));
            });
          }
        })

더 간단한 방법이 있을 것 같지만 현재로선 이것이 최선이었습니다...🤗
어쨌든 해결!✨

+ 덧

흐름은 그대로 쓰고, 코드만 리펙토링 해보았다. 불필요한 .then()이 한 번 줄었다.

let aPromise;
let bPromise;
   if (조건문1) {
      aPromise = fetch
                  .get('uri')
                  .then((res1) => res1)
                  .catch(() => {})
   }
   if (조건문2) {
       bPromise = fetch
                   .get('uri')
                   .then((res2) => res2)
                   .catch(() => {});
   }
return Promise.all([aPromise, bPromise].filter((promise) => promise));
})
  .then((twoDepthArr) => {
       setResult([].concat.apply([], twoDepthArr));
  })

+ 덧2

데이터가 null일 때 만들어지는 promise는 위 코드처럼 filter로 걸러낼 수 없다!
Be Careful with Async Functions that Return Booleans

a Promise object is not one of the eight falsy values in JavaScript, so checking its truthiness is pointless: When coerced to a boolean, a Promise is always true.

promise는 false로 치지 않는 타입이므로, 강제로 체크할 경우 무조건 true로 확인된다는 뜻.
그러므로, 데이터가 null로 올 경우를 거르고 싶다면 two depth array로 변환된 다음에 걸러야 유효하다.

let aPromise;
let bPromise;
   if (조건문1) {
      aPromise = fetch
                  .get('uri')
                  .then((res1) => res1)
                  .catch(() => {})
   }
   if (조건문2) {
       bPromise = fetch
                   .get('uri')
                   .then((res2) => res2)
                   .catch(() => {});
   }
return Promise.all([aPromise, bPromise]);
})
  .then((twoDepthArr) => {
     // 방어 코드
     const filterArr = twoDepthArr.filter((item) => Boolean(item));
     setResult([].concat.apply([], filterArr));
  })

1개의 댓글

comment-user-thumbnail
2023년 1월 9일

Promise.allSettled([promise1, promise2, ...])를 사용해보세요.
allSettled는 { status, value 또는 reason }을 리턴하는데요. promise가 resolve될 경우 value, reject 될 경우 reason이 됩니다. status는 fulfilled 또는 rejected가 되구요. allSettled를 사용하면 프라미스가 실패할 경우를 조치해줄 수 있어서 편리해요.
그리고 프라미스를 다룰때 많이 쓰이는게 async 함수인데요. 함수를 만들때 async 키워드를 사용하여 비동기 함수로 만들고, 내부에서 await을 이용해서 결과값을 동기적으로 처리할 수 있어요.
아래 간단한 예시를 적어봤어요.
function async combinePromise (promise1, promise2) {
// promise들의 결과를 result에 담고, result를 순회하며 value에 담겨있는 객체(보통 api 결과는 객체형태일 것으로 예상)를 합쳐준다.
const result = await Promise.allSettled([promise1(), promise2()])
return result.reduce((a,b) => ({ ...a.value, ...b.value }))
}
열공하세요! 화이팅~! 💪

답글 달기