初期表示処理でいっぱいapi呼んでformを作成しないといけない時のRxJSの書き方(最適化版)


この記事の概要

前回の記事の呼び方は適切でなかったので今回は下記の呼び方で実装します。

[1].
- [1-1]データA・Bを並行で取得
- [1-2]データD・E・Fを並行で取得
[2].データC取得
[3].その他非同期処理(form作成の事前準備)

上記[1]・[2]・[3]を並行で処理後、取得したデータでformを作成する

(前回の方法ではデータC取得処理とその他非同期処理も終わらなければデータD・E・F取得処理に進めない)

実装


ngOnInit() {
  // [1][2][3]を並行で処理
  forkJoin(
    // ここから[1]
    forkJoin(
      // ここから[1-1]。A・B取得処理を並行
      this.fetchA(),
      this.fetchB()
      // ここまで[1-1]
    ).pipe(
      // [1-2]処理後
      // ここから[1-2]
      flatMap(([dataA, dataB]) =>
        // D・E・F取得処理を並行。AとBの取得結果も後続の処理に返す
        forkJoin(
          of(dataA),
          of(dataB),
          this.fetchD(dataA),
          this.fetchE(dataB),
          this.fetchF(dataA, dataB)
        )
      )
      // ここまで[1-2]
    ),
    // ここまで[1]
    this.fetchC(), // [2]
    this.otherObservableFn() // [3]
  ).pipe(
  // [1][2][3]処理後
    /*
     * ※resの中は
     * [
     *   [dataA, dataB, dataD, dataE, dataF], // [1]
     *   dataC, // [2]
     *   otherFn // [3]
     *  ]
     * です
     */
  ).subscribe(res => {
    this.createForm(res);
    this.showScreen = true;
  });
}

ちょっとリファクタリング

[1]は関数分けた方が可読性が良いと思います
また、JSON形式で必要なデータのみcreateFormに渡すようにしてみます


ngOnInit() {
  forkJoin(
    this.fetchBaseData(),
    this.fetchC(),
    this.otherObservableFn()
  ).pipe(
    /*
     * resの中身:
     * [
     *   { dataA, dataB, dataD, dataE, dataF }
     *   , dataC
     *   , otherObservableFnの戻り
     * ]
     * ここからmapでdataCもJSON形式に組み込み、
     * otherObservableFnの戻りを除外して
     * フォームに必要なデータだけ後続に返すようにする。
     */
    map(res => Object.assign({}, { ...res[0] }, { dataC: res[1] })
    // res2の中身: { dataA, dataB, dataD, dataE, dataF, dataC }
  ).subscribe(res2 => {
    this.createForm(res2);
    this.showScreen = true;
  );
}

// ※戻りの型は定義した方が良いです。
private fetchBaseData(): Observable<{ dataA: AModel, dataB: BModel, dataD: DModel, dataE: EModel, dataF: FModel }> {
  return forkJoin(this.fetchA(), this.fetchB()).pipe(
    flatMap(([dataA, dataB]) =>
      forkJoin(
        of(dataA),
        of(dataB),
        this.fetchD(dataA),
        this.fetchE(dataB),
        this.fetchF(dataA, dataB)
      )
    ),
    // JSON型で返すようにする
    map(res => {
      return {
        dataA: res[0],
        dataB: res[1],
        dataD: res[2],
        dataE: res[3],
        dataF: res[4]
      };
    })
  );
}