Skip to content

통계페이지 렌더링을 빠르게 하기 대작전

yejineee edited this page Dec 15, 2020 · 2 revisions

아무리 생각해도 느리다...😭

통계 페이지에 들어갔을 경우, 파이차트와 라인차트는 마음속으로 3초를 세야 보여졌다. 이 3초를 기다리지 못하면, 사용자는 '분명 데이터가 있는데, 내역이 왜 부족하다고 할까'라고 생각할 것이다. 그도 아니면, 렌더링 되지 않는 화면이 답답해서 통계페이지를 넘어가버릴 것이다...

통계페이지를 눌렀을 때, 뽝하고 파이차트와 라인차트가 보여지도록 하고 싶었다! 목표를 이루기 위해 내가 시도한 방법들을 정리해보았다.

🔥 첫 번째 시도 : await을 바꿔보자!

통계페이지에서는 [파이차트의 데이터] 와 [라인차트의 데이터]가 필요하다. 파이차트의 데이터는 getCategoryStatistics API를 호출하면 얻을 수 있다. 라인차트의 데이터는 loadTransactions API로 거래내역을 받아온다.

기존 코드는 두 API를 각각 await으로 기다려 주었다. 사실 두 데이터는 연관관계가 없으므로, 둘 다 await으로 기다려줄 필요는 없어보였다.

파이차트와 라인차트의 데이터를 불러오는 loadAndSetStatistics 함수를 개발자도구로 렌더링 되는 속도를 비교해보고자 하였다.

- 기존 : 둘 다 await 했을 경우 => 🕓 12ms

const loadAndSetStatistics = async () => {
    const loadedStatistics: any = await api.getCategoryStatistics(
      TransactionStore.accountObjId,
      TransactionStore.getDates(),
    );
    setStatistics(loadedStatistics);
    await TransactionStore.loadTransactions();
  };
  useEffect(() => {
    loadAndSetStatistics();
  }

- 수정 : 하나만 await했을 경우 => 🕓 6ms

파이차트 데이터는 await으로 기다려준 후, state에 넣어줘야 하므로 파이차트 데이터만 await을 하는 것으로 변경해 보았다.

const loadAndSetStatistics = async () => {
    TransactionStore.loadTransactions();

    const loadedStatistics: any = await api.getCategoryStatistics(
      TransactionStore.accountObjId,
      TransactionStore.getDates(),
    );
    setStatistics(loadedStatistics);

  };
  useEffect(() => {
    loadAndSetStatistics();
  }, []);

- 결과

둘 중 하나만 await을 했을 경우 -6ms 시간을 단축할 수 있었다.

하지만, 기존보다 조금 나아진 정도이지, 여전히 통계페이지의 첫 로딩은 느렸다.

🔥 두 번째 시도 : API를 한 번만 호출하고, 프론트에서 데이터를 가공하자

기존에는 파이차트와 라인차트의 데이터를 가공을 백엔드와 프론트에서 나눠서 하기에 API 호출을 2번 해야 했다.

파이차트도 라인차트처럼 프론트에서 필요한 형식으로 데이터를 가공한다면, 백엔드 API 호출을 한 번만 보낼 수 있을 것이다. 따라서 백엔드 API 호출을 한 번만 하고 파이차트의 데이터도 프론트에서 가공하는 것으로 수정해보고자 하였따.

- 기존

파이차트 데이터 -> 백엔드에서 가공 후 전달 라인차트 데이터 -> 거래내역 데이터를 한 번 load한 후, 프론트에서 가공

- 수정

거래내역 데이터를 한 번 load한 후 파이차트 데이터 -> 프론트에서 가공 라인차트 데이터 -> 프론트에서 가공

각각의 데이터 가공은 MobX의 computed 함수로 구현하였다.

//파이차트 데이터
  get pieChartStatistics(): types.IStatistics {
    const totalPrice = this.totalPricesExceptFilterAndUnclassified;
    const totalCategoryObj = calTotalPriceByCategories(this.transactionList);
    const incomeCategories = addPercentAndGetArray(
      totalCategoryObj.totalIncomeCategoryObj,
      totalPrice.income,
    );
    const expenseCategories = addPercentAndGetArray(
      totalCategoryObj.totalExpenseCategoryObj,
      totalPrice.expense,
    );
    return { totalPrice, incomeCategories, expenseCategories };
  },
//라인차트 데이터
  get totalExpensePriceByDate() {
    return calTotalPriceByDateAndType(this.transactions, categoryType.EXPENSE);
  },

- 결과

눈으로도 파이차트가 렌더링되는 속도가 빨라졌음을 느낄 수 있었다. 다만, 파이차트는 바로 보여지지만, 라인차트의 데이터는 시간이 지난 후 보여졌다.

🔥 세 번째 시도 : 라인차트의 데이터 또한, 데이터가 로드되는 것을 기다리지 말자

- 분석

두 번째 시도의 결과, 파이차트는 바로 데이터가 보여졌지만, 라인차트는 시간이 지난 후 보여졌다. 이 차이는 파이차트는 데이터가 로드되기를 기다리지 않고, 바로 computed로 계산된 값을 렌더링하지만, 라인차트는 백엔드로부터 데이터가 온 것을 확인한 후, computed로 계산된 값을 렌더링하기 때문에 생겼다.

우리 팀은 공용가계부를 고려하기 때문에, 페이지가 이동될 때마다 새롭게 데이터를 백엔드에서 가져오도록 하였다. 그렇기에 데이터를 불러와야 하긴 하지만, 이전 페이지에서의 observable의 값으로 계산된 결과를 먼저 렌더링해주고, 백엔드로부터 데이터가 도착하여 observable이 변경되었을 때 다시 계산된 결과로 렌더링하는 것 또한 괜찮아 보였다.

- 수정

따라서 라인차트 또한, 데이터가 로드된 것을 기다리지 않고, 우선 이전 데이터로 계산된 데이터를 가져온 후, observable이 변경되어 새로운 데이터가 생길 경우, 다시 렌더링하는 것으로 변경하였다.

- 결과

홈에서 통계페이지로 넘어갔을 때, 라인차트 또한 파이차트처럼 바로 데이터가 보여졌다. 이후 백엔드로부터 데이터가 도착하여 다시 렌더링되는 것을 확인할 수 있었다.

그러나 여전히 문제가 있었다... 이전 페이지에서 불러온 데이터와 통계페이지에서 새롭게 데이터를 불러왔을 때, 티가 나지 않는다. 그러나, 통계 페이지에서 새롭게 불러온 데이터가 이전 데이터와 다르다면 화면이 급격하게 변경되는 것이 보였다.

Clone this wiki locally