📑

複数のデータ取得処理を高速にする

に公開

トップページなど情報量が多いページは、複数のfetch処理ををする場合があります。どのように実装する事が適切か説明します。

1つずつデータを取得

fetchTopPageDataを内で、様々なデータを取得する為複数のfetchを実行しています。1つずつデータを取得する直列タイプです。
今は2つのfetchですが、fetch処理が増えると待ち時間が増えます。

type FetchResponse<T> = Promise<
  | {
      isSuccess: true;
      data: T;
    }
  | {
      isSuccess: false;
    }
>;

type Fruit = {
  name: string;
  type: 'Apple' | 'Banana' | 'Peach';
};
const fetchFruits = (): FetchResponse<Fruit[]> => 'データ取得処理...';

type Food = {
  name: string;
  type: 'Meat' | 'Vegetable' | 'Dessert';
};
const fetchFoods = (): FetchResponse<Food[]> => 'データ取得処理...';

/**
 * トップページで使用する様々なデータを取得する
 */
const fetchTopPageData = async () => {
  const fruits = await fetchFruits();
  if (!fruits.isSuccess) {
    return 'fruits: 取得失敗';
  }

  const foods = await fetchFoods();
  if (!foods.isSuccess) {
    return 'foods: 取得失敗';
  }

  return {
    fruits,
    foods,
  };
};

並列でデータを取得

Promise.allを使用して並列でデータを取得します。fetchFruitsfetchFoods並列で実行する為1つずつデータを取得するより早いです。実行結果は、Promise.allに渡した順番で返却されます。以下の例では、fruits, foodsです。

// 省略...

/**
 * トップページで取得する様々なデータを取得する
 */
const fetchTopPageData = async () => {
  const [fruits, foods] = await Promise.all([fetchFruits(), fetchFoods()]);

  if (!fruits.isSuccess) {
    return 'fruits: 取得失敗';
  }

  if (!foods.isSuccess) {
    return 'foods: 取得失敗';
  }

  return {
    fruits,
    foods,
  };
};

前提条件があるデータ取得処理

並列でデータを取得した方が速度的には早いですが、全ての状況で使える訳ではありません。前提条件があるような処理は、個別に取得した後Promise.allで取得します。
例えば、RoleAdminの場合にデータを取得する場合は、以下のように実装します。

  • fetchRoleのレスポンスがAdminである事を確認をする
  • Adminの場合でPromise.allを使用して並列でデータ取得する
type FetchResponse<T> = Promise<
  | {
      isSuccess: true;
      data: T;
    }
  | {
      isSuccess: false;
    }
>;

type Role = {
  type: 'Admin' | 'Member';
};
type FetchRole = (p: { id: string }) => FetchResponse<Role>;
const fetchRole: FetchRole = () => 'データ取得処理...';

type Store = {
  name: string;
  address: string;
};
type FetchStores = () => FetchResponse<Store[]>;
const fetchStores: FetchStores = () => 'データ取得処理...';

type Employee = {
  id: string;
  name: string;
};
type FetchEmployees = () => FetchResponse<Employee[]>;
const fetchEmployees: FetchEmployees = () => 'データ取得処理...';

const fetchX = () => {};

const main = async () => {
  const role = await fetchRole({ id: 'myId' });

  if (!role.isSuccess) {
    return '権限取得失敗';
  }

  if (role.data.type !== 'Admin') {
    return '権限がありません。';
  }

  const [stores, employees] = await Promise.all([
    fetchStores(),
    fetchEmployees(),
  ]);

  if (!stores.isSuccess) {
    return '店舗一覧取得失敗しました。';
  }

  if (!employees.isSuccess) {
    return '従業員一覧取得失敗しました。';
  }

  return {
    stores,
    employees,
  };
};
chot Inc. tech blog

Discussion