| Typ | Entität |
|---|---|
| Kategorie | werkzeug |
| Quellen | Quelle - Angular Mastery Workshop Quelle - Recherche - Angular heute 2026 |
| Erstellt | 2026-09-26 |
| Aktualisiert | 2026-09-26 |
| Tags | software, bibliothek, javascript, rxjs, reaktive-programmierung |
„Reactive Extensions for JavaScript“: eine Bibliothek für reaktive Programmierung mit Observables und Operatoren, voll typisiert in TypeScript. Angular verwendet sie für HttpClient, Reactive Forms und Router-Ereignisse.
Code-Beispiele aus Quelle - Angular Mastery Workshop (Folie 261–281), von den Folienbildern abgeschrieben.
Eckdaten aus der Quelle
- Sehr mächtig, aber mit Lernkurve. Das Gespür für gute Ströme wächst mit der Zeit (Folie 261).
- Gute Dokumentation auf rxjs.dev mit Marble-Diagrammen (Werte als Kugeln auf einer Zeitachse) und einem Assistenten zur Wahl des passenden Operators (Folie 262).
- Zwei Arten von Operatoren: Erzeuger (aus Timeout, Intervall, Klick …) und Pipe-Operatoren, die das Verhalten eines Stroms ändern. Für fast jeden Bedarf gibt es schon einen Operator oder eine Kombination, sonst schreibt man einen eigenen (Folie 273).
Die häufigsten Operatoren
from([1, 2, 3]).pipe(map(value => value * 2)).subscribe(res => console.log(res)); // 2, 4, 6
from([1, 2, 3]).pipe(filter(value => value < 2)).subscribe(res => console.log(res)); // 1
from([1, 2, 3]).pipe(take(2)).subscribe(res => console.log(res)); // 1, 2
from([1, 2, 3]).pipe(startWith(0)).subscribe(res => console.log(res)); // 0, 1, 2, 3
from([1, 2, 3]).pipe(scan((result, next) => result + next, 0)).subscribe(res => console.log(res)); // 1, 3, 6
(Folie 274)
Folie 274 gibt für map(value => value * 2) das Ergebnis „2, 3, 6“ an. Richtig ist 2, 4, 6.
scan ist das reduce für Ströme: Es gibt nach jedem Wert das Zwischenergebnis aus, nicht nur am Ende.
Flattening-Operatoren
Gibt ein Operator selbst wieder ein Observable zurück, etwa eine Backend-Anfrage pro Suchbegriff, braucht man immer einen Flattening-Operator. Er macht aus einem Strom von Observables einen Strom von Werten (Folie 275):
this.searchForm.valueChanges
.pipe(
debounceTime(300),
switchMap(data => this.searchService.search(data.query)), // liefert ein Observable
map(result => result.user) // einfaches map für den Wert
);
Welcher Operator passt, hängt vom Fall ab (Folie 276–277):
| Operator | Verhalten | Typischer Einsatz |
|---|---|---|
mergeMap (flatMap) |
alle inneren Ströme sofort und parallel | Entitäten anlegen, ändern oder löschen, Reihenfolge egal |
concatMap |
nacheinander | Änderungen, bei denen die Reihenfolge zählt (Handel, Verträge) |
switchMap |
neuer Wert bricht den alten ab | Daten laden, nur die neueste Antwort zählt (verhindert Race Conditions) |
exhaustMap |
ignoriert neue Werte, bis der laufende fertig ist | periodisch senden, überspringen, wenn die letzte Anfrage noch läuft |
Subjects
Ein Subject ist zugleich Observable und Observer, man kann also Werte hineinschieben. Es eignet sich für Ereignisse wie @Output oder destroy (Folie 278):
- BehaviorSubject hält den letzten Wert, ReplaySubject die letzten n Werte.
- Subjects sind multicast: Alle Abonnenten teilen sich eine Quelle.
Das BehaviorSubject-Muster für einfache Stores in Services (Folie 279). Das Subject ist privat, damit Komponenten nicht direkt schreiben können. Nach aussen gibt es nur ein lesbares Observable und Methoden zum Ändern:
@Injectable({
providedIn: 'root'
})
export class UserService {
private model = new BehaviorSubject<User[]>([]); // privat: kein Schreibzugriff von aussen
users: Observable<User[]> = this.model.asObservable(); // öffentlich: nur lesen
constructor(private httpClient: HttpClient) {}
loadUsers() { // Methoden zum Ändern
this.httpClient.get<User[]>(RESOURCE_URL).subscribe(this.model);
}
}
(Siehe State Management.)
Testen
Der eingebaute TestScheduler entfernt die echte Zeit aus Tests. Ströme beschreibt man in Marble-Syntax: - ist ein Zeitschritt, Buchstaben sind Werte, | ist das Ende (Folie 280–281):
import { TestScheduler } from 'rxjs/testing';
describe('Some stream test', () => {
let testScheduler: TestScheduler;
beforeEach(() => {
testScheduler = new TestScheduler((actual, expected) => expect(actual).toEqual(expected));
});
it('Doubles the values after delay', () => {
testScheduler.run(({ cold, expectObservable }) => {
const source = cold('a--b--c---|', { a: 1, b: 2, c: 3 });
const stream = source.pipe(
delay(10),
map(value => value * 2)
);
expectObservable(stream).toBe('10ms a--b--c---|', {
a: 2,
b: 4,
c: 6
});
});
});
});
(Siehe auch Softwaretest.)
Seit Angular Signals eingeführt hat, ist RxJS nicht mehr die einzige Form der Reaktivität in Angular (siehe Reaktive Programmierung). Formulare (Signal Forms) und das Laden von Daten (httpResource) gehen heute auch ohne RxJS (Quelle - Recherche - Angular heute 2026). Für komplexe Ereignisfolgen bleibt RxJS das Mittel der Wahl. Seit RxJS 7 kommen die Operatoren direkt aus 'rxjs', der Pfad 'rxjs/operators' ist nicht mehr nötig (nicht eigens recherchiert).
Verwandt
- Reaktive Programmierung – das Paradigma hinter RxJS
- NgRx – baut auf RxJS auf
- Angular – nutzt RxJS in HttpClient, Router und Formularen
- Angular-Backend-Kommunikation –
catchError,tapin Interceptors
