그 간 많은 일들이 있었다 내가 가보고 싶은 곳의 면접도 보고 결과가 어찌 되었든 최선을 다했다고 생각한다.
본론으로 들어가서
꼭 이런 경우가 있는건 아니지만, 테스트를 하기위해,
const fetchTodos = () =>
axios.get<Todos[]>("https://jsonplaceholder.typicode.com/todos");
const fetchTodoItem = () =>
axios.get<TodoItem[]>("https://jsonplaceholder.typicode.com/todos/1");
const fetchAllTodo = () =>
Promise.all([
fetchTodos(),
fetchTodoItem(),
fetchTodos(),
fetchTodoItem(),
]);
이렇게 중복으로 호출 하는 값이 있다고 보자
그러면 네트워크에 정확하게 4번의 값이 찍힐 것이다.
나의 예상은 적중했다 👍
하지만 우리는 알고 있다 중복 호출에 대해서는 값을 캐싱하고 반환해주면 된다는 것을 그리하여 작업을 시작했다.
const createJsFetchCache = () => {
const cache = new Map();
return (url: string): Promise<AxiosResponse<Todo[] | TodoItem[]>> => {
if (cache.has(url)) {
return cache.get(url);
}
const request = axios.get<Todo[] | TodoItem[]>(url);
cache.set(url, request);
request
.catch(() => {
cache.delete(url);
});
return request;
};
};
const jsFetchCache = createJsFetchCache();
const fetchTodos = () =>
jsFetchCache("https://jsonplaceholder.typicode.com/todos");
const fetchTodoItem = () =>
jsFetchCache("https://jsonplaceholder.typicode.com/todos/1");
처음에는, 클로져를 이용할려 하지 않고, cache를 전역으로 관리하는 코드로 작성을 해보기도 했다 물론 그렇다고 해서 결과값이나 동작이 달라지진 않았다 하지만 주제가 클로져인 관계로 클로져로 작성을 했다
네트워크 에서도 2번만 찍히는 모습을 볼 수 있다.
처음 if문에서는 캐싱된 값이 없어 넘어갈 것이다, 여기서 중요한것은 Promise 자체를 바로 cache에 저장함으로서, Promise.all 을 사용한 병렬에도 중복 호출을 하지 않게 한다, 그 결과 이행 상태가 되면 값을 반환을 한다. 추가로 request에서 에러가 날 경우,
먼저 set을 해준 부분을 삭제 처리하는 로직까지 넣어두긴 했다.
TTL, Size 등을 생각해서 추가로 작성 한다면 더 좋은 캐싱 전략이 될꺼 같기도 하다
const jsFetchCache = createJsFetchCache();
// 해당 부분이 귀찮다고 생각이 들면,
const createJsFetchCache = (() => {
const cache = new Map();
// 내용 생략...
};
})();
즉시실행 함수로 변경하여,
const fetchTodos = () => createJsFetchCache("/schedules-majors.json");
const fetchTodoItem = () =>
createJsFetchCache("/schedules-liberal-arts.json");
하는 것도 가능하다
cache 값을 클로져의 경우 내부에서 관리해서 외부 접근이 불가능 하지만, 클로져 활용 ❌ 에서는 외부 접근이 가능하여 잘못된 접근이나 의도치 않은 수정으로 인해 문제가 발생할 수 있으며, 모듈화 에서도 차이가 발생
(클로져를 사용한 경우는 독립적인 캐싱 인스턴스를 활용할 수 있지만, 하지 않은 예시에서는 불가능 하다)
개인적이지만, 사용하지 않은 쪽이 조금 더 직관적이고 간결해 보이기도 하다.(지극히 개인적)