Skip to content

Arten von Subject

Neben dem grundlegenden Subject bietet RxJS mehrere abgeleitete Klassen, die auf spezifische Anwendungsfälle spezialisiert sind. Jede hat unterschiedliche Verhaltensmerkmale, und durch ihre Verwendung in geeigneten Situationen wird effektiveres reaktives Programmieren möglich.

Hier werden die vier Hauptarten von Subject, ihre Eigenschaften und Anwendungsszenarien detailliert erklärt.

Die vier grundlegenden Subject-Arten

ArtMerkmaleHauptanwendungsfälle
SubjectDas einfachste Subject
Empfängt nur Werte nach dem Abonnement
Event-Benachrichtigung, Multicast
BehaviorSubjectSpeichert den aktuellsten Wert und stellt ihn bei neuem Abonnement sofort bereitState Management, aktuelle Werte von UI-Komponenten
ReplaySubjectGibt eine bestimmte Anzahl vergangener Werte an neue Abonnenten wiederOperationshistorie, aktuelle Update-Informationen
AsyncSubjectGibt nur den letzten Wert beim Abschluss ausHTTP/API-Anfrageergebnisse

Standard-Subject

📘 RxJS Official: Subject

Der einfachste Typ von Subject, der nur nach dem Abonnement auftretende Werte empfängt.

ts
import { Subject } from 'rxjs';

const subject = new Subject<number>();

// Kein Anfangswert, empfängt beim Abonnement nichts
subject.subscribe(value => console.log('Observer 1:', value));

subject.next(1);
subject.next(2);

// Zweites Abonnement (empfängt nur Werte nach dem Abonnement)
subject.subscribe(value => console.log('Observer 2:', value));

subject.next(3);
subject.complete();

Ausführungsergebnis

Observer 1: 1
Observer 1: 2
Observer 1: 3
Observer 2: 3

BehaviorSubject

📘 RxJS Official: BehaviorSubject

Benötigt einen Anfangswert und speichert immer den aktuellsten Wert. Neue Abonnenten erhalten beim Abonnement sofort den aktuellsten Wert.

ts
import { BehaviorSubject } from 'rxjs';

// Mit Anfangswert 0 erstellen
const behaviorSubject = new BehaviorSubject<number>(0);

// Empfängt sofort den Anfangswert
behaviorSubject.subscribe(value => console.log('Observer 1:', value));

behaviorSubject.next(1);
behaviorSubject.next(2);

// Zweites Abonnement (empfängt sofort aktuellsten Wert 2)
behaviorSubject.subscribe(value => console.log('Observer 2:', value));

behaviorSubject.next(3);
behaviorSubject.complete();

Ausführungsergebnis

Observer 1: 0
Observer 1: 1
Observer 1: 2
Observer 2: 2
Observer 1: 3
Observer 2: 3

Anwendungsbeispiele von BehaviorSubject

Verwaltung des Benutzerauthentifizierungsstatus

ts
import { BehaviorSubject } from 'rxjs';

interface User {
  id: string;
  name: string;
}

// Anfangswert ist null (nicht angemeldet)
const currentUser$ = new BehaviorSubject<User | null>(null);

// Anmeldestatus in Komponenten usw. überwachen
currentUser$.subscribe(user => {
  if (user) {
    console.log(`Angemeldet: ${user.name}`);
  } else {
    console.log('Nicht angemeldet');
  }
});

// Anmeldeverarbeitung
function login(user: User) {
  currentUser$.next(user);
}

// Abmeldeverarbeitung
function logout() {
  currentUser$.next(null);
}

// Verwendungsbeispiel
console.log('Anwendungsstart');
// → Nicht angemeldet

login({ id: 'user123', name: 'Taro Yamada' });
// → Angemeldet: Taro Yamada

logout();
// → Nicht angemeldet

Ausführungsergebnis

sh
Nicht angemeldet
Anwendungsstart
Angemeldet: Taro Yamada
Nicht angemeldet

ReplaySubject

📘 RxJS Official: ReplaySubject

Speichert eine bestimmte Anzahl vergangener Werte und sendet sie an neue Abonnenten erneut. Puffergröße und Zeitfenster können eingestellt werden.

ts
import { ReplaySubject } from 'rxjs';

// Puffert die letzten 3 Werte
const replaySubject = new ReplaySubject<number>(3);

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

// Abonnement starten (empfängt die letzten 3 Werte 2,3,4)
replaySubject.subscribe(value => console.log('Observer 1:', value));

replaySubject.next(5);

// Zweites Abonnement (empfängt die letzten 3 Werte 3,4,5)
replaySubject.subscribe(value => console.log('Observer 2:', value));

replaySubject.complete();

Ausführungsergebnis

Observer 1: 2
Observer 1: 3
Observer 1: 4
Observer 1: 5
Observer 2: 3
Observer 2: 4
Observer 2: 5

ReplaySubject mit Zeitfenster

Zeitbasiertes Puffern ist ebenfalls möglich.

ts
import { ReplaySubject } from 'rxjs';

// Maximal 5 Werte und Werte innerhalb von 500ms puffern
const timeWindowSubject = new ReplaySubject<number>(5, 500);

timeWindowSubject.next(1);

setTimeout(() => {
  timeWindowSubject.next(2);

  // Nach 1000ms abonnieren (1 wird nicht empfangen, da Zeitfenster von 500ms überschritten)
  setTimeout(() => {
    timeWindowSubject.subscribe(value => console.log('Empfangen:', value));
  }, 1000);
}, 100);

Ausführungsergebnis

Empfangen: 2

Anwendungsbeispiele von ReplaySubject

Verwaltung der Suchhistorie

ts
import { ReplaySubject } from 'rxjs';

// Speichert die letzten 5 Suchanfragen
const searchHistory$ = new ReplaySubject<string>(5);

// Suchausführungsfunktion
function search(query: string) {
  console.log(`Suche ausführen: ${query}`);
  searchHistory$.next(query);
  // Tatsächliche Suchverarbeitung...
}

// Komponente zur Anzeige der Suchhistorie
function showSearchHistory() {
  console.log('--- Suchhistorie ---');
  searchHistory$.subscribe(query => {
    console.log(query);
  });
}

// Verwendungsbeispiel
search('TypeScript');
search('RxJS');
search('Angular');
search('React');

showSearchHistory();
// Zeigt die letzten 5 (in diesem Fall 4) Suchhistorie-Einträge an

Ausführungsergebnis

sh
Suche ausführen: TypeScript
Suche ausführen: RxJS
Suche ausführen: Angular
Suche ausführen: React
--- Suchhistorie ---
TypeScript
RxJS
Angular
React

AsyncSubject

📘 RxJS Official: AsyncSubject

Subject, das nur den letzten Wert beim Abschluss ausgibt. Werte vor dem Abschluss werden nicht ausgegeben.

ts
import { AsyncSubject } from 'rxjs';

const asyncSubject = new AsyncSubject<number>();

asyncSubject.subscribe(value => console.log('Observer 1:', value));

asyncSubject.next(1);
asyncSubject.next(2);
asyncSubject.next(3);

// Unabhängig vom Zeitpunkt des Abonnements wird nur der letzte Wert empfangen
asyncSubject.subscribe(value => console.log('Observer 2:', value));

asyncSubject.next(4);
asyncSubject.complete(); // Beim Abschluss wird der letzte Wert (4) ausgegeben

Ausführungsergebnis

Observer 1: 4
Observer 2: 4

Anwendungsbeispiele von AsyncSubject

Teilen von API-Anfrageergebnissen

ts
import { AsyncSubject } from 'rxjs';

interface ApiResponse {
  data: any;
  status: number;
}

function fetchData(url: string) {
  const subject = new AsyncSubject<ApiResponse>();

  // API-Anfrage simulieren
  console.log(`API-Anfrage: ${url}`);
  setTimeout(() => {
    const response = {
      data: { id: 1, name: 'Beispieldaten' },
      status: 200
    };

    subject.next(response);
    subject.complete();
  }, 1000);

  return subject;
}

// Verwendungsbeispiel
const data$ = fetchData('/api/users/1');

// Mehrere Komponenten können dasselbe Anfrageergebnis teilen
data$.subscribe(response => {
  console.log('Komponente 1:', response.data);
});

setTimeout(() => {
  data$.subscribe(response => {
    console.log('Komponente 2:', response.data);
  });
}, 1500); // Kann auch nach Abschluss den Wert empfangen

Ausführungsergebnis

sh
API-Anfrage: /api/users/1
Komponente 1: {id: 1, name: 'Beispieldaten'}
Komponente 2: {id: 1, name: 'Beispieldaten'}

Vergleich und Auswahlhilfe für verschiedene Subjects

Nützliche Punkte bei der Auswahl des Subject-Typs werden zusammengefasst.

Auswahlkriterien für Subject

TypAuswahlkriterien
SubjectFür einfache Event-Benachrichtigungen oder Multicast-Verteilung
BehaviorSubject
  • Wenn Anfangswert immer erforderlich
  • Daten, die den aktuellen Zustand repräsentieren (Benutzerstatus, Einstellungen, Flags usw.)
  • Aktuelle Werte von UI-Komponenten
  • ReplaySubject
  • Wenn kürzliche Operationshistorie gespeichert werden muss
  • Wenn später beitretenden Abonnenten vergangene Daten bereitgestellt werden sollen
  • Gepufferte Datenstreams
  • AsyncSubject
  • Wenn nur das Endergebnis wichtig ist (wie API-Antworten)
  • Wenn Zwischenergebnisse unnötig sind und nur der Wert beim Abschluss geteilt werden soll
  • Entscheidungsfluss zur Auswahl

    1. Nur der letzte Wert beim Abschluss erforderlich ⇨ AsyncSubject
    2. Letzte N Werte erforderlich ⇨ ReplaySubject
    3. Aktueller Status/Wert immer erforderlich ⇨ BehaviorSubject
    4. Alles andere (reine Event-Benachrichtigung usw.) ⇨ Subject

    Anwendungspatterns im Anwendungsdesign

    Beispiel für modulübergreifende Kommunikation

    ts
    // Zustandsverwaltungsservice der gesamten Anwendung
    class AppStateService {
      // Aktueller Benutzer (BehaviorSubject, da Anfangswert erforderlich)
      private userSubject = new BehaviorSubject<User | null>(null);
      // Als read-only Observable veröffentlichen
      readonly user$ = this.userSubject.asObservable();
    
      // Benachrichtigung (Subject, da einfache Event-Benachrichtigung)
      private notificationSubject = new Subject<Notification>();
      readonly notifications$ = this.notificationSubject.asObservable();
    
      // Kürzliche Suchen (ReplaySubject, da Historie erforderlich)
      private searchHistorySubject = new ReplaySubject<string>(10);
      readonly searchHistory$ = this.searchHistorySubject.asObservable();
    
      // API-Aufruf-Ergebnis-Cache (AsyncSubject, da nur Endergebnis erforderlich)
      private readonly apiCaches = new Map<string, AsyncSubject<any>>();
    
      // Methodenbeispiele
      setUser(user: User | null) {
        this.userSubject.next(user);
      }
    
      notify(notification: Notification) {
        this.notificationSubject.next(notification);
      }
    
      addSearch(query: string) {
        this.searchHistorySubject.next(query);
      }
    
      // API-Ergebnis-Caching
      fetchData(url: string): Observable<any> {
        if (!this.apiCaches.has(url)) {
          const subject = new AsyncSubject<any>();
          this.apiCaches.set(url, subject);
    
          // Tatsächlicher API-Aufruf
          fetch(url)
            .then(res => res.json())
            .then(data => {
              subject.next(data);
              subject.complete();
            })
            .catch(err => {
              subject.error(err);
            });
        }
    
        return this.apiCaches.get(url)!.asObservable();
      }
    }

    Zusammenfassung

    RxJS Subject ist ein leistungsstarkes Tool, das verschiedene Anwendungsfälle abdeckt. Durch Verständnis der Eigenschaften jedes Typs und deren angemessene Nutzung können effiziente und wartbare reaktive Anwendungen erstellt werden.

    • Subject: Am einfachsten, bietet grundlegende Multicast-Funktionalität
    • BehaviorSubject: Speichert immer den aktuellen Zustand und stellt ihn sofort neuen Abonnenten bereit
    • ReplaySubject: Speichert Historie der letzten Werte und stellt sie auch später beitretenden Abonnenten bereit
    • AsyncSubject: Gibt nur den Endwert beim Abschluss aus

    Die Auswahl des geeigneten Subject für State Management, Event-Benachrichtigung, Datenaustausch usw. ist der Schlüssel zu effektivem reaktiven Programmieren.

    Veröffentlicht unter CC-BY-4.0-Lizenz.