갈수록 복잡한 애플리케이션들이 다양해지는 요즘, API 호출 횟수를 아무리 줄인다 하더라도 어쩔 수 없이 2개 이상의 API를 호출해야하는 경우가 빈번하다. 이럴 때, await
키워드로 API 각각을 따로 호출하기 보다는 Axios.all()
또는 Promise.all()
을 이용해보는 것은 어떨까?
만약 SSR 을 통해 messages
, users
라는 데이터를 return 해주는 API 2개를 호출하는 로직을 기본적인 방법으로 구현하려면 아래와 같다.
기본 방법
export const getServerSideProps = async () => {
const { messages } = await fetcher(GET_MESSAGES);
const { users } = await fetcher(GET_USERS); // 위의 fetcher(GET_MESSAGES) 호출이 완전히 완료되어야 호출됨.
return {
props: {
serverSideMessages: messages ?? [],
users: users ?? []
}
};
};
이렇게 작성해도 기능상으로는 잘 작동하지만, API return data가 큰 경우에는 성능상의 문제가 발생할 수도 있다. 위의 코드의 문제점은 아래와 같다.
await fetcher
API 호출 함수가 순차적으로(동기적으로) 호출됨.
이 말은 즉, 위의 코드를 기준으로 봤을 떄 messages
데이터를 불러오는 fetcher(GET_MESSAGES)
API 함수가 가장 먼저 호출되며 resolve()
또는 fulfilled
를 반환하기 전까지는 fetcher(GET_USERS)
API 함수는 호출되지 않는다는 의미이다. 이렇게 되면 모든 데이터가 완전히 로드되기 까지의 소요 시간이 불필요하게 길어질 수 있다.
따라서, 이런 경우 아래의 방법들로 해당 이슈를 개선할 수 있다.
Promise.all(Awaited[ ])
await
키워드를 붙인다..all()
메서드의 인자에 삽입한다.messages
, users
를 바로 정의하였다. export const getServerSideProps = async () => {
const [{ messages }, { users }] = await Promise.all([
fetcher(GET_MESSAGES),
fetcher(GET_USERS)
]);
return {
props: {
serverSideMessages: messages ?? [],
users: users ?? []
}
};
};
axios.all(Awaited[ ])
.all()
메서드의 인자에 삽입한다..all()
메서드에 .then(axios.apread(res1, res2, ...) => {...})
함수 내부에서 Array 에 들어있는 API 호출 함수 index 기준으로 return data를 핸들링 할 수 있다.spread()
파라미터를 생략하여 es6의 객체 구조 분해 할당 문법을 사용할 수도 있다.import axios from 'Axios';
export const getServerSideProps = async () => {
const { messages, users } = axios.all([fetcher(GET_MESSAGES), fetcher(GET_USERS)]).then(axios.spread());
return {
props: {
serverSideMessages: messages ?? [],
users: users ?? []
}
};
}