時間のかかる処理が終わるまで待ってから結果を返す、終わってたらすぐに返す

ユースケース

  1. 画面A の開始時に、時間のかかるデータ読み込みを開始する
  2. 画面A でなんやかんや操作した後、画面B へ移動
  3. 画面B では Aで読み込んだデータが必要なので、読み込みが完了するまで待つ

実現方法

readonly data$ = new BehaviorSubject<string[]>(undefined);

// 画面Aで時間のかかるデータ読み込み
setTimeout(() => {
  this.data$.next(['a', 'b', 'c'])
}, 1000);

// すぐに画面Bへ移動した場合、読み込み完了まで待つ
firstValueFrom(this.data$.pipe(filter(x => x != null))).then(x => {
  console.log('a', x);
});

// 読み込みが終わってから画面Bへ移動した場合、すぐに結果を返す
setTimeout(() => {
  firstValueFrom(this.data$.pipe(filter(x => x != null))).then(x => {
    console.log('b', x);
  });
}, 2000);

書いてみるとなんの事はなく、BehaviourSubject と Observable→Promise 変換を使えば簡単だった。 BehaviourSubject は「最新の結果を保持し、subscribe されたらそれを通知する」という特性があるので、BehaviourSubject を Promise 化すると、すぐに結果が返される。 ここで初期値(undefined)を無視すれば、「何らかの値が通知されたら結果を返却するPromise」 になる。