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
| Art | Merkmale | Hauptanwendungsfälle |
|---|---|---|
Subject | Das einfachste Subject Empfängt nur Werte nach dem Abonnement | Event-Benachrichtigung, Multicast |
BehaviorSubject | Speichert den aktuellsten Wert und stellt ihn bei neuem Abonnement sofort bereit | State Management, aktuelle Werte von UI-Komponenten |
ReplaySubject | Gibt eine bestimmte Anzahl vergangener Werte an neue Abonnenten wieder | Operationshistorie, aktuelle Update-Informationen |
AsyncSubject | Gibt nur den letzten Wert beim Abschluss aus | HTTP/API-Anfrageergebnisse |
Standard-Subject
Der einfachste Typ von Subject, der nur nach dem Abonnement auftretende Werte empfängt.
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: 3BehaviorSubject
📘 RxJS Official: BehaviorSubject
Benötigt einen Anfangswert und speichert immer den aktuellsten Wert. Neue Abonnenten erhalten beim Abonnement sofort den aktuellsten Wert.
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: 3Anwendungsbeispiele von BehaviorSubject
Verwaltung des Benutzerauthentifizierungsstatus
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 angemeldetAusführungsergebnis
Nicht angemeldet
Anwendungsstart
Angemeldet: Taro Yamada
Nicht angemeldetReplaySubject
📘 RxJS Official: ReplaySubject
Speichert eine bestimmte Anzahl vergangener Werte und sendet sie an neue Abonnenten erneut. Puffergröße und Zeitfenster können eingestellt werden.
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: 5ReplaySubject mit Zeitfenster
Zeitbasiertes Puffern ist ebenfalls möglich.
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: 2Anwendungsbeispiele von ReplaySubject
Verwaltung der Suchhistorie
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 anAusführungsergebnis
Suche ausführen: TypeScript
Suche ausführen: RxJS
Suche ausführen: Angular
Suche ausführen: React
--- Suchhistorie ---
TypeScript
RxJS
Angular
ReactAsyncSubject
Subject, das nur den letzten Wert beim Abschluss ausgibt. Werte vor dem Abschluss werden nicht ausgegeben.
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) ausgegebenAusführungsergebnis
Observer 1: 4
Observer 2: 4Anwendungsbeispiele von AsyncSubject
Teilen von API-Anfrageergebnissen
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 empfangenAusführungsergebnis
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
| Typ | Auswahlkriterien |
|---|---|
Subject | Für einfache Event-Benachrichtigungen oder Multicast-Verteilung |
BehaviorSubject | |
ReplaySubject | |
AsyncSubject |
Entscheidungsfluss zur Auswahl
- Nur der letzte Wert beim Abschluss erforderlich ⇨
AsyncSubject - Letzte N Werte erforderlich ⇨
ReplaySubject - Aktueller Status/Wert immer erforderlich ⇨
BehaviorSubject - Alles andere (reine Event-Benachrichtigung usw.) ⇨
Subject
Anwendungspatterns im Anwendungsdesign
Beispiel für modulübergreifende Kommunikation
// 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ätBehaviorSubject: Speichert immer den aktuellen Zustand und stellt ihn sofort neuen Abonnenten bereitReplaySubject: Speichert Historie der letzten Werte und stellt sie auch später beitretenden Abonnenten bereitAsyncSubject: 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.