序章

RxJSのsubjectは、オブザーバブルとオブザーバーの両方として同時に機能できる特別なハイブリッドです。 このようにして、データをサブジェクトにプッシュすることができ、サブジェクトのサブスクライバーは、プッシュされたデータを受信します。

サブジェクトは、マルチキャストや、データのソースを簡単に監視可能なものに変換できない場合に役立ちます。 この優れた投稿に示されているように、被写体を使いすぎるのは簡単です。それ以外の方法で観測可能なソースを作成できる場合は、被写体を避けることができます。

この投稿では、主題、行動主題、およびリプレイ主題について学びます。

前提条件

この記事をフォローしたい場合は、次のものが必要になります。

このチュートリアルは、rxjsv7.3.0で検証されました。

主題の使用

サブジェクトの作成は、RxJSのSubjectの新しいインスタンスから始まります。

const mySubject = new Rx.Subject();

複数のサブスクリプションを作成することができ、内部的にサブジェクトはサブスクリプションのリストを保持します。

const subscription1 = mySubject.subscribe(x => console.log(`${x} ${x}`));

const subscription2 = mySubject.subscribe(x => console.log(x.toUpperCase()));

nextメソッドを使用して、データをサブジェクトにプッシュできます。

mySubject.next('Hello!');

このスクリプトを実行すると、次の出力が生成されます。

Output
Hello! Hello! HELLO!

subscription1の場合、このコードは入力を受け取り、それを2回表示します。 subscription2の場合、このコードは入力を受け取り、toUpperCase()を適用します。

データがサブジェクトにプッシュされると、サブスクリプションの内部リストを調べ、データをそれぞれにnextします。

サブスクリプションへのデータのプッシュ

データがサブスクリプションにプッシュされる方法を示す例を次に示します。

const mySubject = new Rx.Subject();

mySubject.next(1);

const subscription1 = mySubject.subscribe(x => {
  console.log('From subscription 1:', x);
});

mySubject.next(2);

const subscription2 = mySubject.subscribe(x => {
  console.log('From subscription 2:', x);
});

mySubject.next(3);

subscription1.unsubscribe();

mySubject.next(4);

この例では、コンソールに出力される結果は次のとおりです。

Output
From subscription 1: 2 From subscription 1: 3 From subscription 2: 3 From subscription 2: 4

サブジェクトにプッシュされたデータの一部で、遅れて到着したサブスクリプションがどのように欠落しているかに注意してください。 後で行動サブジェクトまたはリプレイサブジェクトでこれに対処する方法を説明します。

すべてのサブスクリプションへのデータのマルチキャスト

サブジェクトの真の力は、マルチキャストで機能します。この場合、サブジェクトはオブザーバブルとしてオブザーバブルに渡されます。つまり、オブザーバブルが放出されると、データはサブジェクトのすべてのサブスクリプションにマルチキャストされます。

これは、trickleWordsオブザーバブルが750msごとに単語を出力する例です。

const mySubject = new Rx.Subject();

const words = ['Hot Dog', 'Pizza', 'Hamburger'];

const trickleWords = Rx.Observable.zip(
  Rx.Observable.from(words),
  Rx.Observable.interval(750),
  word => word
);

const subscription1 = mySubject.subscribe(x => {
  console.log(x.toUpperCase());
});

const subscription2 = mySubject.subscribe(x => {
  console.log(
    x
      .toLowerCase()
      .split('')
      .reverse()
      .join('')
  );
});

trickleWords.subscribe(mySubject);

これにより、すべての値が出力された後、次の出力が生成されます。

Output
HOT DOG god toh PIZZA azzip HAMBURGER regrubmah

subscription1の場合、wordsの配列がtoUpperCase()で変更されています。 subscription2の場合、wordsの配列がtoLowerCase()と“ reverse()`で変更されています。

asObservableを使用する

asObservable演算子を使用して、被写体を観測量に変換できます。 これは、サブジェクトからのデータを公開すると同時に、データが誤ってサブジェクトにプッシュされるのを防ぐ場合に役立ちます。

const mySubject = new Rx.Subject();
const myObservable = mySubject.asObservable();

mySubject.next('Hello');
myObservable.next('World!');

これにより、次の出力が生成されます。

Output
TypeError: myObservable.next is not a function

myObservableは、nexterror、またはcompleteを所有していません。

エラーの処理

サブジェクトが完了するかエラーになると、すべての内部サブスクリプションも完了するかエラーになります。

const mySubject = new Rx.Subject();

const subscription1 = mySubject.subscribe(null, error =>
  console.log('From subscription 1:', error.message)
);

const subscription2 = mySubject.subscribe(null, error =>
  console.log('From subscription 2:', error.message)
);

mySubject.error(new Error('Error!'));

これにより、次の出力が生成されます。

Output
From subscription 1: Error! From subscription 2: Error!

エラーメッセージが生成されました。

リプレイサブジェクトの使用

前に説明したように、サブジェクトのサブスクリプションが遅れると、以前に発行されたデータが失われます。 リプレイサブジェクトは、新しいサブスクリプションに発行される以前の値のバッファーを保持することで、これを支援できます。

これは、以前の2つの値のバッファーが保持され、新しいサブスクリプションで発行されるリプレイサブジェクトの使用例です。

const mySubject = new Rx.ReplaySubject(2);

mySubject.next(1);
mySubject.next(2);
mySubject.next(3);
mySubject.next(4);

mySubject.subscribe(x => {
  console.log('From subscription 1:', x);
});

mySubject.next(5);

mySubject.subscribe(x => {
  console.log('From subscription 2:', x);
});

これにより、次の出力が生成されます。

Output
From subscription 1: 3 From subscription 1: 4 From subscription 1: 5 From subscription 2: 4 From subscription 2: 5

2つの値のバッファーが保管されています。

行動主体の使用

動作サブジェクトはリプレイサブジェクトに似ていますが、最後に発行された値、または以前に発行された値がない場合はデフォルト値のみを再発行します。

const mySubject = new Rx.BehaviorSubject('Hello!');

mySubject.subscribe(x => {
  console.log('From subscription 1:', x);
});

mySubject.next(5);

mySubject.subscribe(x => {
  console.log('From subscription 2:', x);
});

これにより、次の出力が生成されます。

Output
From subscription 1: Hello! From subscription 1: 5 From subscription 2: 5

デフォルトのHello!値が発行されました。

結論

この投稿では、主題、行動主題、およびリプレイ主題について学びました。

RxJSバッファリング演算子の概要 RxJS:From演算子、およびtakeUntilRxJS演算子を使用してサブスクリプションを宣言的に管理する方法で学習を続けてください。