【RxJS】combineLatestオペレータとは?「使い方」や「特徴」などを解説!

この記事ではRxJSの『combineLatestオペレータ』について、以下の内容を図とサンプルコードを用いて分かりやすく解説します。

  • combineLatestオペレータとは
  • combineLatestオペレータの「使い方」
  • combineLatestオペレータの「特徴」

RxJSのcombineLatestとは

RxJSのcombineLatestとは

RxJSのcombineLatestは、複数のObservableを入力として取り、それぞれのObservableの最新の値を組み合わせて新しいObservableを出力するオペレータです。

以下にcombineLatestを用いたサンプルコードを示します。

import { combineLatest, timer } from 'rxjs';

// 1000ms後に0を出力し、その後1000ms秒ごとに「1→2→3→4→・・・」というデータを流すObservable
const timerOne$ = timer(1000, 1000);

// 1500ms後に0を出力し、その後1000ms秒ごとに「1→2→3→4→・・・」というデータを流すObservable
const timerTwo$ = timer(1500, 1000);

// combineLatestを使用して、2つのObservableの最新の値を組み合わせて新しいObservableを出力する
const combined$ = combineLatest([timerOne$, timerTwo$]);

combined$.subscribe((value) => console.log(value));

// ログ
// [ 0, 0 ]
// [ 1, 0 ]
// [ 1, 1 ]
// [ 2, 1 ]
// [ 2, 2 ]
// [ 3, 2 ]
// [ 3, 3 ]
// [ 4, 3 ]

上記のサンプルコードでは、combineLatestを使用して、2つのObservable(timerOne$timerTwo$)の最新の値を組み合わせて新しいObservableを出力しています。

あわせて読みたい

timerオペレータ』については下記の記事で詳しく説明しています。興味のある方は下記のリンクからぜひチェックをしてみてください。

combineLatestの返り値は配列のObservableなので、以下のプログラムに示すように、配列の分割代入を使用することもできます。

import { combineLatest, timer } from 'rxjs';

// 1000ms後に0を出力し、その後1000ms秒ごとに「1→2→3→4→・・・」というデータを流すObservable
const timerOne$ = timer(1000, 1000);

// 1500ms後に0を出力し、その後1000ms秒ごとに「1→2→3→4→・・・」というデータを流すObservable
const timerTwo$ = timer(1500, 1000);

// combineLatestを使用して、2つのObservableの最新の値を組み合わせて新しいObservableを出力する
const combined$ = combineLatest([timerOne$, timerTwo$]);

// 配列の分割代入を使用
combined$.subscribe(([timerValueOne, timerValueTwo]) => {
  console.log(`Timer One:${timerValueOne}  Timer Two:${timerValueTwo}`);
});

// ログ
// Timer One:0  Timer Two:0
// Timer One:1  Timer Two:0
// Timer One:1  Timer Two:1
// Timer One:2  Timer Two:1
// Timer One:2  Timer Two:2
// Timer One:3  Timer Two:2
// Timer One:3  Timer Two:3
// Timer One:4  Timer Two:3

また、以下に示すように、combineLatestは関数を用いて、Observableの形を変更することもできます。

import { combineLatest, timer } from 'rxjs';

// 1000ms後に0を出力し、その後1000ms秒ごとに「1→2→3→4→・・・」というデータを流すObservable
const timerOne$ = timer(1000, 1000);

// 1500ms後に0を出力し、その後1000ms秒ごとに「1→2→3→4→・・・」というデータを流すObservable
const timerTwo$ = timer(1500, 1000);

// combineLatestを使用して、2つのObservableの最新の値を組み合わせて新しいObservableを出力する
// 関数を用いて、組み合わせたObservableの形を変更することもできる
const combined$ = combineLatest([timerOne$, timerTwo$], (timerValueOne, timerValueTwo) => {
  let timeradd = timerValueOne + timerValueTwo;
  return `Timer One(${timerValueOne}) + Timer Two(${timerValueTwo}) = ${timeradd}`;
});

combined$.subscribe((value) => console.log(value));

// ログ
// Timer One(0) + Timer Two(0) = 0
// Timer One(1) + Timer Two(0) = 1
// Timer One(1) + Timer Two(1) = 2
// Timer One(2) + Timer Two(1) = 3
// Timer One(2) + Timer Two(2) = 4
// Timer One(3) + Timer Two(2) = 5
// Timer One(3) + Timer Two(3) = 6
// Timer One(4) + Timer Two(3) = 7

combineLatestの特徴

combineLatestの特徴を以下に示します。

  • 全てのObservableが値を発行するまで出力されない
    • combineLatestは、組み合わせる全てのObservableが最初の値を発行するまで何も出力しません。そのため、いずれかのObservableが遅れて値を発行する場合には注意が必要です。
  • 各Observableの発行がトリガーとなる
    • 全てのObservableが一度値を発行した後は、どのObservableが値を発行しても、その最新の値を組み合わせて出力されます

上記の特徴が分かるサンプルコードをこれから説明します。

全てのObservableが値を発行するまで出力されない

全てのObservableが値を発行するまで出力されない

combineLatestは、組み合わせる全てのObservableが最初の値を発行するまで何も出力しません。サンプルコードを以下に示します。

以下のプログラムを見てみましょう。

import { combineLatest, timer } from 'rxjs';

// 1000ms後に0を出力し、その後1000ms秒ごとに「1→2→3→4→・・・」というデータを流すObservable
const timerOne$ = timer(1000, 1000);

// 1500ms後に0を出力し、その後1000ms秒ごとに「1→2→3→4→・・・」というデータを流すObservable
const timerTwo$ = timer(1500, 1000);

// 3750ms後に0を出力し、その後1000ms秒ごとに「1→2→3→4→・・・」というデータを流すObservable
const timerThree$ = timer(3750, 1000);

// combineLatestを使用して、3つのObservableの最新の値を組み合わせて新しいObservableを出力する
const combined$ = combineLatest([timerOne$, timerTwo$, timerThree$]);

combined$.subscribe((value) => console.log(value));

// ログ
// [ 2, 2, 0 ]
// [ 3, 2, 0 ]
// [ 3, 3, 0 ]
// [ 3, 3, 1 ]
// [ 4, 3, 1 ]
// [ 4, 4, 1 ]
// [ 4, 4, 2 ]
// [ 5, 4, 2 ]
// [ 5, 5, 2 ]
// [ 5, 5, 3 ]
// [ 6, 5, 3 ]
// [ 6, 6, 3 ]

combineLatestは、全てのObservableから少なくとも一度はデータが発行されるまで、何も出力しません、このプログラムでは、3750ms後に最初の値を発行するObservable(timerThree$)があります。したがって、Observable(timerThree$)が発行されるまで、combineLatestは何も出力しません。

各Observableの発行がトリガーとなる

各Observableの発行がトリガーとなる

全てのObservableが一度値を発行した後は、どのObservableが値を発行しても、その最新の値を組み合わせて出力されます。サンプルコードを以下に示します。

import { combineLatest, timer } from 'rxjs';

// 1000ms後に0を出力し、その後1000ms秒ごとに「1→2→3→4→・・・」というデータを流すObservable
const timerOne$ = timer(1000, 1000);

// 1500ms後に0を出力し、その後1000ms秒ごとに「1→2→3→4→・・・」というデータを流すObservable
const timerTwo$ = timer(1500, 1000);

// combineLatestを使用して、2つのObservableの最新の値を組み合わせて新しいObservableを出力する
const combined$ = combineLatest([timerOne$, timerTwo$]);

combined$.subscribe((value) => console.log(value));

// ログ
// [ 0, 0 ]
// [ 1, 0 ]
// [ 1, 1 ]
// [ 2, 1 ]
// [ 2, 2 ]
// [ 3, 2 ]
// [ 3, 3 ]
// [ 4, 3 ]

この例では、timerTwo$が1000msごと、timerOne$が1500msごとに値を発行します。それぞれのObservableが値を発行するたびに、その最新の値を組み合わせて出力されていることがわかります。

補足

オペレーターの動作を理解する上で、以下のサイトが非常に便利です。発行されるObservableを移動させたりして、各オペレーターの動作を確認できます。

https://rxmarbles.com/

本記事のまとめ

この記事ではRxJSの『combineLatestオペレータ』について、以下の内容を説明しました。

  • combineLatestオペレータとは
  • combineLatestオペレータの「使い方」
  • combineLatestオペレータの「特徴」

お読み頂きありがとうございました。