AngularでのSubject vs BehaviorSubject vs ReplaySubject


122

私はそれらを理解しようと努めてきました3:

件名行動件名リプレイ件名。私はそれらを使用したいと思います、いつ、なぜ、それらを使用する利点は何ですか、そして私はドキュメントを読み、チュートリアルを見て、googleを検索しましたが、これを理解できませんでした。

では、それらの目的は何ですか?実際のケースでは、コードを書く必要がないことを最も評価します。

「a + b => cあなたが購読している...」だけでなく、わかりやすい説明を希望します。

ありがとうございました


1
観察可能な行動主体に関する質問はすでにあります。stackoverflow.com/questions/39494058/...と再生対象のドキュメントは芋明らかであるgithub.com/Reactive-Extensions/RxJS/blob/master/doc/api/...
EKO

この回答では、Rxjsの主題が比較的完全に表現されています。これは、peeksiletからの回答をうまく補完します。これには、終了後の動作に関する重要な詳細も含まれるため、確認することをお勧めします。
user3743222 2017年

回答:


277

それは実際には行動と意味論に帰着します。とともに

  • Subject-サブスクライバーは、サブスクリプション後に発行された公開値のみを取得します。自問してください、それはあなたが欲しいものですか?加入者は以前の値について何かを知る必要がありますか?そうでない場合は、これを使用できます。それ以外の場合は、他のいずれかを選択します。たとえば、コンポーネント間の通信を使用します。ボタンのクリックで他のコンポーネントのイベントを発行するコンポーネントがあるとします。件名付きのサービスを利用して通信することができます。

  • BehaviorSubject-最後の値がキャッシュされます。サブスクライバーは、最初のサブスクリプション時に最新の値を取得します。この主題のセマンティクスは、時間とともに変化する値を表すことです。たとえば、ログインしているユーザー。最初のユーザーは匿名ユーザーである可能性があります。ただし、ユーザーがログインすると、新しい値は認証されたユーザーの状態になります。

    BehaviorSubject初期値で初期化されます。これは、コーディング設定にとって重要な場合があります。たとえば、で初期化するとしnullます。次に、サブスクリプションでnullチェックを実行する必要があります。多分大丈夫、または多分迷惑です。

  • ReplaySubject-指定された数の排出までキャッシュできます。サブスクライバーは、サブスクリプション時にすべてのキャッシュされた値を取得します。この動作はいつ必要になりますか?正直なところ、次の場合を除いて、そのような動作は必要ありませんでした。

    ReplaySubjectバッファサイズで初期化すると、1実際にはと同じように動作BehaviorSubjectます。最後の値は常にキャッシュされるため、時間とともに変化する値のように機能します。これによりnull、でBehaviorSubject初期化する場合のようにチェックする必要がありませんnull。この場合、最初の公開まで、値はサブスクライバーに発行されません。

したがって、実際に期待する動作(どちらを使用するか)に依存します。ほとんどのBehaviorSubject場合、実際に表現したいのはその「時間に対する価値」のセマンティクスであるため、おそらくaを使用することになります。しかし、個人的には、でReplaySubject初期化されたの置換に問題があるとは思いません1

避けたいのは、Subject本当に必要なのがキャッシング動作であるときにバニラを使用することです。たとえば、ルーティングガードまたは解決を記述しているとします。そのガードでデータをフェッチし、サービスに設定しますSubject。次に、ルーティングされたコンポーネントで、サービスサブジェクトにサブスクライブして、ガードで発行されたその値を取得しようとします。おっとっと。価値はどこにありますか?すでに放出された、DUH。「キャッシュ」サブジェクトを使用してください!

以下も参照してください。


1
これは短く、違いを理解しやすいです。サービスで値が変更され、コンポーネントもその値が表示されるように変更される場合、BehaviourSubjectsまたはReplay Subjectが解決策です。
サイヤフファルーク、

1
ありがとうございました!ReplaySubjectバッファサイズが1の場合は、まさに私が必要としていたサイズです。値が必要なルートガードがありましたが、最初の放出を待つ必要がありました。つまり、BehaviorSubject私は初期値nullが必要ないので(それを使用して州を示すために機能しないので)、それをカットしていませんでした
menehune23

1
@ menehune23 Angular resolveガードクラスのReplaySubjectも必要でした。データサービスは、非同期または同期(データが既に取得されている場合)にすることができます。同期の場合、resolve関数が返され、Angularが内部でサブスクライブする前に、Subject.next()が起動されていました。BehaviourSubjectはおそらく機能しますが、明示的に呼び出して、初期値のチェックcomplete()も追加する必要がありnullます。効果があったのは新しくReplaySubject<DataType>(1)resolveSubject.asObservable().take(1).map(....)
Drenai

1
バッファサイズが1のReplaySubjectを使用していますが、何らかの理由で、ObservableでObservableを取得した場合、ReplaySubjectを呼び出す前にサブスクライバに.asObservable()値を送信します。BehaviorSubjectとは異なり、初期値があるはずではないと思いましたか?nullnext()
カイルV.

2
リプレイの件名について言及できるかなり簡単な例は、新しい参加者に最後の10個のメッセージを表示させたい「チャットルーム」またはゲームロビーのシナリオの場合でしょう。
ジェームズ

14

さまざまな観察可能なタイプの簡単な要約、直感的ない名前付けは知っていますlol

  • Subject -サブスクライバーは、サブスクリプションが作成された後、その上で公開された値のみを取得します。
  • BehaviorSubject -新しいサブスクライバーは、サブスクリプションの直後に、最後に公開された値または初期値を取得します。
  • ReplaySubject -新しい購読者は、購読するとすぐに以前に公開されたすべての値を取得します

1-n公開された値?したがって、2つの公開値がある場合、ReplaySubjectは-1の公開値を生成しますか?
Jason Cheng

@JasonChengいいえ、サブスクリプション時に以前に発行されたすべての値を取得します。回答を更新します:)
Ricky Boyce

11
  1. 件名:サブスクライブすると、サブスクリプション後にプッシュされるデータが常に取得されます。つまり、以前にプッシュされた値は受信されません
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);

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

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

サブジェクトにプッシュされたデータの一部に遅れて到着するサブスクリプションが欠落していることに注意してください。

  1. リプレイサブジェクト:新しいサブスクリプションに発行される以前の値のバッファーを保持することで役立ちます。

以下は、a buffer of 2 previous valuesが保持され、新しいサブスクリプションで発行されるリプレイサブジェクトの使用例です。

const mySubject = new Rx.ReplaySubject(2);

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

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

mySubject.next(5);

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

これがコンソールで私たちに与えるものです:

From 1st sub: 3
From 1st sub: 4
From 1st sub: 5
From 2nd sub: 4
From 2nd sub: 5
  1. 動作サブジェクト:リプレイサブジェクトに似ていますが、最後に放出された値のみを再放出するか、以前に値が放出されていない場合はデフォルト値を再放出します。
const mySubject = new Rx.BehaviorSubject('Hey now!');

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

mySubject.next(5);

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

そしてその結果:

From 1st sub: Hey now!
From 1st sub: 5
From 2nd sub: 5

リファレンス:https : //alligator.io/rxjs/subjects/


4

From:Randall Koutnikの本「RxJSでリアクティブウェブサイトを構築する」。:

件名は、観察可能なターボチャージャーのオブジェクトです。基本的に、Subjectは通常のオブザーバブルのように動作しますが、各サブスクリプションは同じソースにフックされています。サブジェクトもオブザーバーであり、すべてのサブスクライバーに一度にデータを送信するためのnext、error、doneメソッドがあります。サブジェクトはオブザーバーであるため、サブスクライブ呼び出しに直接渡すことができ、元のオブザーバブルからのすべてのイベントはサブジェクトを通じてサブスクライバーに送信されます。

ReplaySubjectを使用して履歴を追跡できます。A ReplaySubjectは、彼らがすべての新しい加入者に戻り、最後のn個のイベントとpalysを記録します。たとえば、チャットアプリケーションです。以前のチャット履歴の記録を追跡するために使用できます。

A BehaviorSubjectはの簡易版であるReplaySubjectReplaySubjectは、イベントの任意の数、保存されたBehaviorSubjectは唯一、最新のイベントの値を記録します。BehaviorSubjectは、新しいサブスクリプションを記録するたびに、サブスクライバーに最新の値と渡された新しい値を送信します。BehaviorSubjectは、構成オプションなどの単一の状態単位を処理する場合に役立ちます。


1

最も賛成された答えは明らかに次のように主張して間違っています:

ReplaySubject1のバッファサイズでa を初期化すると、実際にはのように動作しますBehaviorSubject


これは完全に真実ではありません。これらの2つの違いについては、この素晴らしいブログ投稿をチェックしてください。たとえば、completedをサブスクライブした場合BehaviorSubject、最後の値は受け取りませんが、a ReplaySubject(1)は最後の値を受け取ります。

これは、見落としてはならない重要な違いです。

const behavior = new BehaviorSubject(null);
const replay = new ReplaySubject(1);

behavior.skip(1).subscribe(v => console.log('BehaviorSubject:', v));
replay.subscribe(v => console.log('ReplaySubject:', v));

behavior.next(1);
behavior.next(2);
behavior.complete();
behavior.subscribe(v => console.log('Late B subscriber:', v));

replay.next(1);
replay.next(2);
replay.complete();
replay.subscribe(v => console.log('Late R subscriber:', v));

このコード例で確認してくださいここから来ている別の偉大なブログ記事トピックのを。


0
     // ***********Subject  concept ***********
    let subject = new Subject<string>();


    subject.next("Eureka");
    subject.subscribe((data) => {
      console.log("Subscriber 1 got data >>>>> "+ data);
    });
    subject.subscribe((data) => {
      console.log("Subscriber 2 got data >>>>> "+ data);
    });

       // ********behaviour subject*********
    // Behavior subjects need a first value
let subject1 = new BehaviorSubject<string>("First value");


subject1.asObservable().subscribe((data) => {
  console.log("First subscriber got data behaviour subject>>>>> "+ data);
});
subject1.next("Second value")
  • サブジェクト-サブスクライバーは、サブスクリプションが作成された後、パブリッシュされた値のみを取得します。
  • BehaviorSubject-新しいサブスクライバーは、サブスクリプションの直後に、最後に公開された値または初期値を取得します。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.