Was ist der Unterschied zwischen BehaviorSubject und Observable?

Lesezeit: 12 Minuten

Kevin Marks Benutzeravatar
Kevin Mark

Ich untersuche die Entwurfsmuster von RxJS und verstehe den Unterschied zwischen ihnen nicht BehaviorSubject Und Observable.

Nach meinem Verständnis kann BehaviorSubject einen Wert enthalten, der sich ändern kann. Es kann abonniert werden und Abonnenten können aktualisierte Werte erhalten. Beide scheinen genau den gleichen Zweck zu haben.

  1. Wann sollte man Observable vs. BehaviorSubject verwenden und umgekehrt?
  2. Welche Vorteile bietet die Verwendung von BehaviorSubject im Gegensatz zu Observable und umgekehrt?

  • Dieser Artikel hat mir besonders geholfen, Observable vs. Subjekte vs. Verhaltenssubjekte auf ELI5-Art zu verstehen javascript.plainenglish.io/…

    – Mike.Alvarez

    31. August 2021 um 15:06 Uhr

Benutzeravatar von Shantanu Bhadoria
Shantanu Bhadoria

BehaviorSubject ist eine Variante von SubjectEine Art von Observable die man wie jedes andere Observable „abonnieren“ kann.

Merkmale von BehaviorSubject

  • Es benötigt einen Anfangswert, da es beim Abonnement immer einen Wert zurückgeben muss, auch wenn es die Methode nicht erhalten hat next()
  • Beim Abonnement wird der letzte Wert des Betreffs zurückgegeben. Ein reguläres Observable wird nur ausgelöst, wenn es die Methode empfängt onNext()
  • Mit der Methode kann man jederzeit den letzten Wert des Subjekts in einem nicht beobachtbaren Objekt abrufen getValue()

Merkmale des Subjekts

  • Das Subjekt ist nicht nur ein Beobachtbarer, sondern auch ein „Beobachter“. Daher kann man auch Werte an ein Subjekt senden und gleichzeitig dieses abonnieren
  • Mit der Methode kann man einen Wert von BehaviorSubject abrufen asObservable()

Beispiel 1 mit BehaviorSubject

// BehaviorSubject.
// 'A' is an initial value. If there is a Subscription 
// after it, it would immediately get the value 'A'.

beSubject = new BehaviorSubject('a'); 

beSubject.next('b');

beSubject.subscribe(value => {
  console.log('Subscription received the value ', value);

  // Subscription received B. It would not happen
  // for an Observable or Subject by default.
});

beSubject.next('c');
// Subscription received C.

beSubject.next('d');
// Subscription received D.

Beispiel 2 mit Betreff

// Subject.

subject = new Subject(); 

subject.next('b');

subject.subscribe(value => {
  console.log('Subscription received the value ', value);

  // Subscription won't receive anything at this point.
});

subject.next('c');
// Subscription received C.

subject.next('d');
// Subscription received D.

Aus beiden kann ein Observable erstellt werden Subject Und BehaviorSubject; Zum Beispiel, subjectName.asObservable().

Der einzige Unterschied besteht darin, dass man mit dieser Methode keine Werte an ein Observable senden kann next().

In Angular wird die Verwendung empfohlen BehaviorSubject zum Übertragen von Daten als Dienst wird häufig vor einer Komponente initialisiert.

BehaviorSubject stellt sicher, dass die Komponente, die den Dienst nutzt, aufgrund des Abonnements der Komponente für den Dienst die zuletzt aktualisierten Daten erhält, auch wenn keine neuen Aktualisierungen vorliegen.

  • Ich bin etwas verwirrt mit Beispiel 2 des regulären Themas. Warum erhält das Abonnement nichts, obwohl Sie in der zweiten Zeile mit subject.next(“b”) Werte an subject senden?

    – jmod999

    11. November 2016 um 17:45 Uhr

  • @jmod999 Das zweite Beispiel ist ein regulärer Betreff, der unmittelbar vor dem Aufruf des Abonnements einen Wert erhält. In regulären Subjekten wird das Abonnement nur für Werte ausgelöst, die nach dem Aufruf des Abonnements empfangen werden. Da eine direkt vor dem Abonnement empfangen wird, wird sie nicht an das Abonnement gesendet.

    – Shantanu Bhadoria

    19. April 2017 um 19:20 Uhr

  • Ich hatte am Mittwoch ein Angular 4-Interview. Da ich mich noch mit der neuen Plattform vertraut mache, brachte er mich zum Stolpern, indem er mich fragte: „Was passiert, wenn ich ein Observable abonniere, das sich in einem Modul befindet, das noch nicht verzögert geladen wurde?“ Ich war mir nicht sicher, aber er sagte mir, dass die Antwort darin bestehe, ein BSubject zu verwenden – GENAU so, wie Herr Bhadoria es oben erklärt hat. Die Antwort war, ein BSubject zu verwenden, weil es immer den neuesten Wert zurückgibt (zumindest erinnere ich mich so an den letzten Kommentar des Interviewers dazu).

    – Bob. Mazzo

    24. November 2017 um 15:48


  • @bob.mazzo Warum muss ich in diesem Fall ein BSubject verwenden? — Wenn ich diesen Beobachter abonniere, erhalte ich nichts, weil der Beobachter nicht initialisiert wurde, sodass er keine Daten an Beobachter senden kann. Wenn ich ein BSubject verwende, erhalte ich aus demselben Grund auch nichts. In beiden Fällen erhält der Abonnent nichts, da er sich in einem Modul befindet, das nicht initialisiert wurde. Habe ich recht?

    – Rafael Reyes

    13. Juni 2018 um 23:03 Uhr

  • Sollte der Dienst nicht einen privaten haben? BehaviourSubject und auf den Wert wird öffentlich zugegriffen Observable welches den Wert des ausgibt BehaviourSubjectalso nicht zulassen next aufgerufen werden BS außerhalb des Dienstes?

    – Emobe

    5. Juni 2019 um 10:08

Vamshis Benutzeravatar
Vamshi

Beobachtbar: Unterschiedliches Ergebnis für jeden Beobachter

Ein sehr, sehr wichtiger Unterschied. Da Observable nur eine Funktion ist, hat es keinen Status und führt daher für jeden neuen Observer den Observable-Erstellungscode immer wieder aus. Das führt zu:

Der Code wird für jeden Beobachter ausgeführt. Wenn es sich um einen HTTP-Aufruf handelt, wird er für jeden Beobachter aufgerufen

Dies führt zu erheblichen Fehlern und Ineffizienzen

BehaviorSubject (oder Subject) speichert Beobachterdetails, führt den Code nur einmal aus und gibt das Ergebnis an alle Beobachter weiter.

Ex:

JSBin: http://jsbin.com/qowulet/edit?js,console

// --- Observable ---
let randomNumGenerator1 = Rx.Observable.create(observer => {
   observer.next(Math.random());
});

let observer1 = randomNumGenerator1
      .subscribe(num => console.log('observer 1: '+ num));

let observer2 = randomNumGenerator1
      .subscribe(num => console.log('observer 2: '+ num));


// ------ BehaviorSubject/ Subject

let randomNumGenerator2 = new Rx.BehaviorSubject(0);
randomNumGenerator2.next(Math.random());

let observer1Subject = randomNumGenerator2
      .subscribe(num=> console.log('observer subject 1: '+ num));
      
let observer2Subject = randomNumGenerator2
      .subscribe(num=> console.log('observer subject 2: '+ num));
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.3/Rx.min.js"></script>

Ausgang :

"observer 1: 0.7184075243594013"
"observer 2: 0.41271850211336103"
"observer subject 1: 0.8034263165479893"
"observer subject 2: 0.8034263165479893"

Beobachten Sie, wie Sie es verwenden Observable.create Für jeden Beobachter wurde eine andere Ausgabe erstellt, aber BehaviorSubject gab für alle Beobachter die gleiche Ausgabe. Das ist wichtig.


Weitere Unterschiede zusammengefasst.

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃         Observable                  ┃     BehaviorSubject/Subject         ┃      
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ 
┃ Is just a function, no state        ┃ Has state. Stores data in memory    ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ Code run for each observer          ┃ Same code run                       ┃
┃                                     ┃ only once for all observers         ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ Creates only Observable             ┃Can create and also listen Observable┃
┃ ( data producer alone )             ┃ ( data producer and consumer )      ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ Usage: Simple Observable with only  ┃ Usage:                              ┃
┃ one Obeserver.                      ┃ * Store data and modify frequently  ┃
┃                                     ┃ * Multiple observers listen to data ┃
┃                                     ┃ * Proxy between Observable  and     ┃
┃                                     ┃   Observer                          ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

  • irgendjemand kommt von KnockoutJS's ko.observable() Ich werde sofort weitere Parallelen zu erkennen Rx.BehaviorSubject im Vergleich zu Rx.Observable

    – Simon_Weaver

    21. Juni 2017 um 21:57 Uhr

  • @Skeptor Beobachtbar: Die subscribe-Methode löst immer die dem Beobachter zugeordnete onNext-Methode aus und liefert den Rückgabewert. VerhaltenBetreff/Betreff: Gibt immer den neuesten Wert im Stream zurück. Hier löst die Subscribe-Methode mit dem Subjekt die onNext-Methode ihres Observers erst aus, wenn sie den neuesten Wert im Stream findet.

    – Mohan Ram

    26. Okt. 2017 um 10:58


Benutzeravatar von Kedar9444
Kedar9444

Beobachtbar Und Thema Beide sind beobachtbar, was bedeutet, dass ein Beobachter sie verfolgen kann. Beide haben einige einzigartige Eigenschaften. Es gibt drei Arten von Themen, von denen jede auch einzigartige Eigenschaften hat.

Das Praxisbeispiel finden Sie hier Stackblitz.
(Sie müssen die Konsole überprüfen, um die tatsächliche Ausgabe zu sehen)

Geben Sie hier eine Bildbeschreibung ein

Observables

Sie sind kalt: Code wird ausgeführt, wenn mindestens ein einzelner Beobachter vorhanden ist.

Erstellt eine Kopie der Daten: Observable erstellt eine Kopie der Daten für jeden Beobachter.

Unidirektional: Der Beobachter kann dem Observablen (Ursprung/Master) keinen Wert zuweisen.

Subject

Sie sind heiß: Code wird ausgeführt und Wert wird gesendet, auch wenn kein Beobachter vorhanden ist.

Gibt Daten weiter: Dieselben Daten werden von allen Beobachtern gemeinsam genutzt.

bidirektional: Der Beobachter kann dem Observablen (Ursprung/Master) einen Wert zuweisen.

Wenn Sie subject verwenden, fehlen Ihnen alle Werte, die vor der Erstellung des Beobachters gesendet werden. Also hier kommt Betreff wiederholen

ReplaySubject

Sie sind heiß: Code wird ausgeführt und der Wert wird gesendet, auch wenn kein Beobachter vorhanden ist.

Gibt Daten weiter: Dieselben Daten werden von allen Beobachtern gemeinsam genutzt.

bidirektional: Der Beobachter kann dem Observablen (Ursprung/Master) einen Wert zuweisen. Plus

Wiederholen Sie den Nachrichtenstream: Unabhängig davon, wann Sie das Wiederholungsthema abonnieren, erhalten Sie alle gesendeten Nachrichten.

In Subject und ReplaySubject können Sie den Anfangswert nicht auf observable setzen. Also hier kommt BehavioralSubject

BehaviorSubject

Sie sind heiß: Code wird ausgeführt und der Wert wird gesendet, auch wenn kein Beobachter vorhanden ist.

Gibt Daten weiter: Dieselben Daten werden von allen Beobachtern gemeinsam genutzt.

bidirektional: Der Beobachter kann dem Observablen (Ursprung/Master) einen Wert zuweisen. Plus

Sie können den Anfangswert festlegen: Sie können das Observable mit einem Standardwert initialisieren.

  • Könnte erwähnenswert sein, dass a ReplaySubject hat eine Historie und kann eine Folge von (alten) Werten senden/senden. Nur wenn buffer auf 1 gesetzt ist, verhält es sich ähnlich wie a BehaviorSubject.

    – Welke

    19. November 2019 um 8:29

  • Für BehaviorSubject scheint der Absatz „Nachrichtenstrom erneut abspielen“ nicht korrekt zu sein

    – Jaqen H’ghar

    19. Dezember 2020 um 7:48 Uhr

Das Observable-Objekt stellt eine Push-basierte Sammlung dar.

Die Observer- und Observable-Schnittstellen bieten einen allgemeinen Mechanismus für Push-basierte Benachrichtigungen, der auch als Observer-Entwurfsmuster bezeichnet wird. Das Observable-Objekt stellt das Objekt dar, das Benachrichtigungen sendet (den Anbieter); Das Observer-Objekt stellt die Klasse dar, die sie empfängt (den Beobachter).

Die Subject-Klasse erbt sowohl Observable als auch Observer in dem Sinne, dass sie sowohl ein Beobachter als auch ein Observable ist. Sie können ein Subjekt verwenden, um alle Beobachter zu abonnieren, und dann das Subjekt bei einer Back-End-Datenquelle abonnieren

var subject = new Rx.Subject();

var subscription = subject.subscribe(
    function (x) { console.log('onNext: ' + x); },
    function (e) { console.log('onError: ' + e.message); },
    function () { console.log('onCompleted'); });

subject.onNext(1);
// => onNext: 1

subject.onNext(2);
// => onNext: 2

subject.onCompleted();
// => onCompleted

subscription.dispose();

Mehr dazu https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/subjects.md

Eine Sache, die ich in Beispielen nicht sehe, ist, dass, wenn Sie BehaviorSubject über asObservable in Observable umwandeln, das Verhalten übernommen wird, den letzten Wert beim Abonnement zurückzugeben.

Das ist der knifflige Teil, da Bibliotheken oft Felder als beobachtbar bereitstellen (z. B. Parameter in ActivatedRoute in Angular2), hinter den Kulissen jedoch möglicherweise Subject oder BehaviorSubject verwenden. Was sie verwenden, würde sich auf das Abonnementverhalten auswirken.

Siehe hier http://jsbin.com/ziquxapubo/edit?html,js,console

let A = new Rx.Subject();
let B = new Rx.BehaviorSubject(0);

A.next(1);
B.next(1);

A.asObservable().subscribe(n => console.log('A', n));
B.asObservable().subscribe(n => console.log('B', n));

A.next(2);
B.next(2);

Ein beobachtbar ermöglicht Ihnen nur das Abonnieren, während a Thema ermöglicht Ihnen sowohl das Veröffentlichen als auch das Abonnieren.

Ein Thema ermöglicht es Ihnen also Dienstleistungen sowohl als Herausgeber als auch als Abonnent verwendet werden.

Im Moment bin ich nicht so gut darin Observable Daher gebe ich hier nur ein Beispiel Subject.

Lassen Sie uns mit einem besser verstehen Angular CLI Beispiel. Führen Sie die folgenden Befehle aus:

npm install -g @angular/cli

ng new angular2-subject

cd angular2-subject

ng serve

Ersetzen Sie den Inhalt von app.component.html mit:

<div *ngIf="message">
  {{message}}
</div>

<app-home>
</app-home>

Führen Sie den Befehl aus ng g c components/home um die Home-Komponente zu generieren. Ersetzen Sie den Inhalt von home.component.html mit:

<input type="text" placeholder="Enter message" #message>
<button type="button" (click)="setMessage(message)" >Send message</button>

#message ist hier die lokale Variable. Fügen Sie eine Eigenschaft hinzu message: string;
zum app.component.ts‘s Klasse.

Führen Sie diesen Befehl aus ng g s service/message. Dadurch wird ein Dienst generiert src\app\service\message.service.ts. Stellen Sie der App diesen Dienst zur Verfügung.

Importieren Subject hinein MessageService. Fügen Sie auch einen Betreff hinzu. Der endgültige Code sollte so aussehen:

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class MessageService {

  public message = new Subject<string>();

  setMessage(value: string) {
    this.message.next(value); //it is publishing this value to all the subscribers that have already subscribed to this message
  }
}

Fügen Sie nun diesen Dienst ein home.component.ts und übergeben Sie eine Instanz davon an den Konstruktor. Tun Sie dies für app.component.ts zu. Verwenden Sie diese Dienstinstanz zum Übergeben des Werts von #message zur Servicefunktion setMessage:

import { Component } from '@angular/core';
import { MessageService } from '../../service/message.service';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent {

  constructor(public messageService:MessageService) { }

  setMessage(event) {
    console.log(event.value);
    this.messageService.setMessage(event.value);
  }
}

Innen app.component.tsabonnieren und abbestellen (um Speicherlecks zu verhindern) für Subject:

import { Component, OnDestroy } from '@angular/core';
import { MessageService } from './service/message.service';
import { Subscription } from 'rxjs/Subscription';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {

  message: string;
  subscription: Subscription;

  constructor(public messageService: MessageService) { }

  ngOnInit() {
    this.subscription = this.messageService.message.subscribe(
      (message) => {
        this.message = message;
      }
    );
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

Das ist es.

Nun kann ein beliebiger Wert eingegeben werden #message von home.component.html soll gedruckt werden {{message}} innen app.component.html

Benutzeravatar von R4L_R4o
R4L_R4o

Denk an Observable wie ein Rohr mit fließendem Wasser, manchmal fließt Wasser und manchmal nicht. In einigen Fällen benötigen Sie möglicherweise tatsächlich ein Rohr, in dem sich immer Wasser befindet. Dies können Sie erreichen, indem Sie ein spezielles Rohr erstellen, das immer Wasser enthält, egal wie klein es ist. Nennen wir dieses spezielle Rohr BehaviorSubjectWenn Sie in Ihrer Gemeinde ein Wasserversorger sind, können Sie nachts ruhig schlafen und wissen, dass Ihr neu installiertes Rohr einfach funktioniert.

Technisch ausgedrückt: Sie können auf Anwendungsfälle stoßen, in denen ein Observable immer einen Wert enthalten sollte. Vielleicht möchten Sie den Wert eines Eingabetextes über einen längeren Zeitraum erfassen. Anschließend können Sie eine Instanz von BehaviorSubject erstellen, um diese Art von Verhalten sicherzustellen, sagen wir:


const firstNameChanges = new BehaviorSubject("<empty>");

// pass value changes.
firstNameChanges.next("Jon");
firstNameChanges.next("Arya");

Anschließend können Sie „Wert“ verwenden, um Änderungen im Laufe der Zeit abzutasten.


firstNameChanges.value;

Dies ist praktisch, wenn Sie Observables später kombinieren. Indem Sie sich den Typ Ihres Streams als BehaviorSubject ansehen, können Sie sicherstellen, dass die Streamen Sie mindestens einmal oder signalisieren Sie mindestens einmal.

  • deckt viele Teile ab, aber das Positive an Ihrer Erklärung ist, dass sie eine leicht verständliche Analogie liefert, Kudo!!!

    – Jeb50

    2. April 2021 um 21:59 Uhr

1454710cookie-checkWas ist der Unterschied zwischen BehaviorSubject und Observable?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy