Betreff vs BehaviorSubject vs ReplaySubject in Angular


122

Ich habe versucht, diese 3 zu verstehen:

Betreff , Verhaltensthema und Wiederholungsfach . Ich möchte sie verwenden und wissen, wann und warum, welche Vorteile sie haben, und obwohl ich die Dokumentation gelesen, Tutorials angesehen und Google durchsucht habe, habe ich keinen Sinn daraus gemacht.

Was ist ihr Zweck? Ein realer Fall wäre sehr dankbar, wenn er nicht einmal codieren müsste.

Ich würde eine saubere Erklärung vorziehen, nicht nur "a + b => c, das Sie abonniert haben ..."

Danke dir


1
Es gibt bereits eine Frage zum Verhaltensthema mit beobachtbar; stackoverflow.com/questions/39494058/… und die Dokumentation zum Thema Wiederholung ist klar imo github.com/Reactive-Extensions/RxJS/blob/master/doc/api/…
eko

Diese Antwort enthält eine relativ gründliche Darstellung der Themen in Rxjs , die die Antwort von peeksilet gut ergänzt. Dies beinhaltet auch wichtige Details zum Verhalten nach der Kündigung, daher ist es gut, einen Blick darauf zu werfen.
user3743222

Antworten:


276

Es kommt wirklich auf Verhalten und Semantik an. Mit einer

  • Subject- Ein Abonnent erhält nur veröffentlichte Werte, die nach dem Abonnement ausgegeben wurden. Fragen Sie sich, ist es das, was Sie wollen? Muss der Abonnent etwas über vorherige Werte wissen? Wenn nicht, können Sie dies verwenden, andernfalls wählen Sie eine der anderen. Zum Beispiel bei der Kommunikation von Komponente zu Komponente. Angenommen, Sie haben eine Komponente, die Ereignisse für andere Komponenten auf Knopfdruck veröffentlicht. Sie können einen Dienst mit einem Betreff zur Kommunikation verwenden.

  • BehaviorSubject- Der letzte Wert wird zwischengespeichert. Ein Abonnent erhält beim ersten Abonnement den neuesten Wert. Die Semantik für dieses Thema besteht darin, einen Wert darzustellen, der sich im Laufe der Zeit ändert. Zum Beispiel ein angemeldeter Benutzer. Der ursprüngliche Benutzer kann ein anonymer Benutzer sein. Sobald sich ein Benutzer anmeldet, ist der neue Wert der authentifizierte Benutzerstatus.

    Das BehaviorSubjectwird mit einem Anfangswert initialisiert. Dies ist manchmal wichtig für die Codierungspräferenz. Angenommen, Sie initialisieren es mit a null. Dann müssen Sie in Ihrem Abonnement eine Nullprüfung durchführen. Vielleicht OK oder vielleicht nervig.

  • ReplaySubject- Es kann bis zu einer bestimmten Anzahl von Emissionen zwischengespeichert werden. Alle Abonnenten erhalten beim Abonnement alle zwischengespeicherten Werte. Wann würden Sie dieses Verhalten brauchen? Ehrlich gesagt hatte ich keine Notwendigkeit für ein solches Verhalten, außer im folgenden Fall:

    Wenn Sie a ReplaySubjectmit einer Puffergröße von initialisieren 1, verhält es sich tatsächlich wie a BehaviorSubject. Der letzte Wert wird immer zwischengespeichert, sodass er sich wie ein Wert verhält, der sich im Laufe der Zeit ändert. Damit ist keine nullPrüfung erforderlich, wie im Fall der BehaviorSubjectmit a initialisierten null. In diesem Fall wird bis zur ersten Veröffentlichung kein Wert an den Abonnenten ausgegeben.

Es kommt also wirklich auf das Verhalten an, das Sie erwarten (für welches Sie es verwenden möchten). Die meiste Zeit werden Sie wahrscheinlich eine verwenden wollen, BehaviorSubjectweil das, was Sie wirklich darstellen möchten, die Semantik "Wert über Zeit" ist. Aber ich persönlich sehe nichts falsches an der Ersetzung von ReplaySubjectinitialisiert durch 1.

Was Sie vermeiden möchten, ist die Verwendung der Vanille, Subjectwenn Sie wirklich ein Caching-Verhalten benötigen. Nehmen wir zum Beispiel, Sie schreiben einen Routing Guard oder eine Lösung. Sie rufen einige Daten in diesem Guard ab und legen sie in einem Dienst fest Subject. Dann abonnieren Sie in der gerouteten Komponente den betreffenden Dienst, um zu versuchen, den Wert zu erhalten, der im Guard ausgegeben wurde. Hoppla. Wo ist der Wert? Es wurde bereits ausgestrahlt, DUH. Verwenden Sie ein "Caching" -Thema!

Siehe auch:


1
Dies ist kurz und leicht zu verstehen, die Unterschiede. Wenn sich der Wert im Service ändert und die Komponenten auch ändern, dass der Wert angezeigt wird, ist BehaviourSubjects oder Replay Subject die Lösung.
Saiyaff Farouk

1
Danke dir! ReplaySubjectmit einer Puffergröße von 1 war genau das, was ich brauchte. Ich hatte einen Streckenwächter, der den Wert brauchte, aber auf die erste Emission warten musste. A BehaviorSubjectschnitt es also nicht ab, da ich keinen Anfangswert wollte ( nullwürde auch nicht funktionieren, weil ich ihn zur Kennzeichnung eines Zustands verwendete)
menehune23

1
@ menehune23 Ich brauchte auch ReplaySubject für eine Angular resolveGuard-Klasse. Mein Datendienst kann asynchron oder synchron sein (wenn die Daten bereits abgerufen wurden). Wenn es synchron war, wurde Subject.next () ausgelöst, bevor die resolveFunktion zurückgegeben und von Angular intern abonniert wurde. BehaviourSubject würde möglicherweise funktionieren, aber ich müsste explizit aufrufen complete()und auch nullÜberprüfungen für den Anfangswert hinzufügen . Was funktionierte war neu ReplaySubject<DataType>(1) undresolveSubject.asObservable().take(1).map(....)
Drenai

1
Ich verwende ein ReplaySubject mit einer Puffergröße von 1, aber aus irgendeinem Grund .asObservable()sende ich, wenn ich ein Observable mit dem Observable erhalte , einen Wert von nullan Abonnenten, bevor ich next()mein ReplaySubject aufrufe. Ich dachte, es sollte im Gegensatz zu BehaviorSubject keinen Anfangswert haben?
Kyle V.

2
Ich denke, ein ziemlich einfaches Beispiel, das Sie für das Thema der Wiederholung erwähnen könnten, wäre ein "Chatroom" - oder Spielelobby-Szenario, in dem neue Tischler die letzten 10 Nachrichten sehen sollen.
James

14

Eine handliche Zusammenfassung der verschiedenen beobachtbaren Typen, nicht intuitive Benennung, die ich kenne lol .

  • Subject - Ein Abonnent erhält erst nach Abschluss des Abonnements veröffentlichte Werte.
  • BehaviorSubject - Neue Abonnenten erhalten unmittelbar nach dem Abonnement den zuletzt veröffentlichten Wert ODER den Anfangswert.
  • ReplaySubject - Neue Abonnenten erhalten alle zuvor veröffentlichten Werte sofort nach dem Abonnement

1-n veröffentlichte Werte? Wenn es also 2 veröffentlichte Werte gäbe, würde ein ReplaySubject -1 veröffentlichte Werte erzeugen ???
Jason Cheng

@JasonCheng nein, es ruft alle zuvor veröffentlichten Werte beim Abonnement ab, Antwort aktualisieren :)
Ricky Boyce

11
  1. Betreff : Beim Abonnieren werden immer die Daten abgerufen, die nach dem Abonnement übertragen werden, dh frühere Push-Werte werden nicht empfangen .
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);

In diesem Beispiel ist hier das Ergebnis, das in der Konsole gedruckt wird:

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

Beachten Sie, dass Abonnements, die zu spät eintreffen, einige der Daten verpassen, die in den Betreff verschoben wurden.

  1. Themen wiedergeben : Kann helfen, indem ein Puffer mit vorherigen Werten aufbewahrt wird, die an neue Abonnements ausgegeben werden.

Hier ist ein Verwendungsbeispiel für Wiedergabethemen, bei denen a buffer of 2 previous valuesfür neue Abonnements beibehalten und ausgegeben wird:

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);
});

Folgendes gibt uns das an der Konsole:

From 1st sub: 3
From 1st sub: 4
From 1st sub: 5
From 2nd sub: 4
From 2nd sub: 5
  1. Verhaltenssubjekte : ähneln Wiederholungssubjekten, geben jedoch nur den zuletzt ausgegebenen Wert oder einen Standardwert erneut aus, wenn zuvor kein Wert ausgegeben wurde:
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);
});

Und das Ergebnis:

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

Referenz: https://alligator.io/rxjs/subjects/


4

Aus: Randall Koutnik Buch „Erstellen Sie reaktive Websites mit RxJS.“ ::

Ein Subjekt ist ein Objekt, das mit Turbolader beobachtet werden kann. Im Kern verhält sich ein Betreff ähnlich wie ein reguläres Observable, aber jedes Abonnement ist an dieselbe Quelle gebunden. Die Probanden sind auch Beobachter und verfügen über Next-, Error- und Doed-Methoden, um Daten gleichzeitig an alle Abonnenten zu senden. Da Subjekte Beobachter sind, können sie direkt an einen Abonnementanruf weitergeleitet werden, und alle Ereignisse aus dem ursprünglichen Observable werden über das Subjekt an seine Abonnenten gesendet.

Wir können das ReplaySubject verwenden, um den Verlauf zu verfolgen. Ein ReplaySubject zeichnet die letzten n Ereignisse auf und sendet sie an jeden neuen Abonnenten zurück. Zum Beispiel in der Chat-Anwendung. Wir können es verwenden, um die Aufzeichnung des vorherigen Chat-Verlaufs zu verfolgen.

Ein BehaviorSubject ist eine vereinfachte Version des ReplaySubject . Das ReplaySubject hat eine beliebige Anzahl von Ereignissen gespeichert, das BehaviorSubject zeichnet nur den Wert des letzten Ereignisses auf. Wenn ein BehaviorSubject ein neues Abonnement aufzeichnet, gibt es den neuesten Wert an den Abonnenten sowie alle neu übergebenen Werte aus. Das BehaviorSubject ist nützlich, wenn es sich um einzelne Statuseinheiten handelt, z. B. Konfigurationsoptionen.


1

Die am meisten befürwortete Antwort ist eindeutig falsch und behauptet:

"Wenn Sie a ReplaySubjectmit einer Puffergröße von 1 initialisieren , verhält es sich tatsächlich wie a. BehaviorSubject"


Das ist nicht ganz richtig; In diesem großartigen Blog-Beitrag erfahren Sie, welche Unterschiede zwischen diesen beiden bestehen. Wenn Sie beispielsweise einen abgeschlossenen abonnieren BehaviorSubject, erhalten Sie nicht den letzten Wert, sondern einen ReplaySubject(1).

Dies ist ein wichtiger Unterschied, der nicht übersehen werden sollte:

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));

Überprüfen Sie dieses Codebeispiel hier, das aus einem anderen großartigen Blog-Beitrag zum Thema stammt.


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")
  • Betreff - Ein Abonnent erhält erst nach Abschluss des Abonnements veröffentlichte Werte.
  • BehaviorSubject - Neue Abonnenten erhalten unmittelbar nach dem Abonnement den zuletzt veröffentlichten Wert ODER den Anfangswert.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.