RxJS in Angular 2026: Operatoren, Subjects und Signals-Interop
RxJS in Angular 2026: Operatoren, Subjects und die Signals-Interop-Muster, die Angular-Entwickler in Produktion nutzen, plus die häufigsten Interviewfragen.

RxJS bleibt in Angular auch 2026 das Rückgrat der asynchronen Programmierung, selbst wenn Signals die Art und Weise verändern, wie Angular-Komponenten synchronen Zustand verfolgen. Zu wissen, wann ein Observable die richtige Wahl ist, wann ein Signal besser passt und wie beide zusammenspielen, gehört heute zum Kernwissen jedes Angular-Entwicklers. Dieser Deep Dive führt durch die Operatoren, Subjects und Interop-Muster, die eine souveräne Interviewantwort von einer ins Stocken geratenen unterscheiden.
Signals modellieren synchronen Zustand, der immer einen aktuellen Wert hat; Observables modellieren asynchrone Ereignisströme über die Zeit. Angular 20 behält beide bei, und das Paket @angular/core/rxjs-interop ist die offizielle Brücke zwischen ihnen.
Warum RxJS neben Angular Signals weiterhin zählt
Die Einführung von Signals ließ viele Teams fragen, ob RxJS auf dem Weg nach draußen sei. Die Antwort lautet drei Hauptversionen später: nein. Signals glänzen bei Zustand, der jetzt einen Wert hat: ein Zähler, ein Formularfeld, ein ausgewählter Tab. Observables glänzen bei Ereignissen, die über die Zeit eintreffen und Transformation, Abbruch oder Kombination erfordern: HTTP-Antworten, WebSocket-Nachrichten, Tastatureingaben, Router-Ereignisse und Timer.
Angulars eigene APIs machen diese Trennung sichtbar. HttpClient liefert nach wie vor Observables. Reactive Forms stellen valueChanges und statusChanges als Observables bereit. Router-Ereignisse fließen durch ein Observable. Überall dort, wo mehrere asynchrone Ereignisse durch denselben Kanal strömen, bleiben RxJS-Operatoren das ausdrucksstärkste verfügbare Werkzeug. Der offizielle Angular-Leitfaden zur Reaktivität behandelt beide Modelle als ergänzend statt konkurrierend, und die RxJS-Dokumentation bleibt eine Pflichtreferenz für jeden nicht-trivialen Datenfluss.
Die praktische Regel, die im Code-Review Bestand hat: Signals für lokalen, im Template gelesenen Komponentenzustand und Observables für asynchrone Pipelines, die Operatoren benötigen. Die Interop-Schicht verbindet beide, sodass kein Modell zur Mauer wird.
Kombinationsoperatoren untermauern diesen Punkt. Mehrere asynchrone Quellen zu koordinieren, etwa Routenparameter mit den gespeicherten Filtern eines Nutzers und einem Live-Preis-Feed zu verschmelzen, ist genau das, wofür combineLatest, withLatestFrom und forkJoin gebaut wurden. Signals können berechnete Werte aus anderen Signals ableiten, aber sie können keine zeitbasierte Koordination ausdrücken wie "gib erst dann aus, wenn alle drei Quellen mindestens einen Wert geliefert haben". Diese deklarative Komposition über die Zeit ist der dauerhafte Grund, warum RxJS im Werkzeugkasten bleibt.
Zentrale RxJS-Operatoren, auf die sich jeder Angular-Entwickler verlässt
Operatoren sind reine Funktionen, die ein Observable entgegennehmen und ein neues zurückgeben. Das klassische Interviewszenario ist die Suche während der Eingabe, weil es vier Operatoren auf einmal beansprucht: die Eingabe drosseln, Duplikate überspringen, veraltete Anfragen abbrechen und Fehler abfangen.
import { Component, inject } from '@angular/core';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
import { debounceTime, distinctUntilChanged, switchMap, catchError } from 'rxjs/operators';
import { of } from 'rxjs';
@Component({
selector: 'app-search',
imports: [ReactiveFormsModule],
template: `<input [formControl]="query" placeholder="Search repositories" />`,
})
export class SearchComponent {
private http = inject(HttpClient);
query = new FormControl('');
results$ = this.query.valueChanges.pipe(
debounceTime(300), // wait until typing pauses for 300ms
distinctUntilChanged(), // ignore emissions that repeat the last value
switchMap((term) => // cancel the in-flight request, start a fresh one
this.http.get(`/api/search?q=${term}`).pipe(
catchError(() => of([])) // recover from a failed request without killing the stream
)
)
);
}Das feine Detail, das Interviewer abklopfen, ist, warum switchMap auf der äußeren Ebene sitzt, während catchError in ihm verschachtelt ist. catchError auf das innere HTTP-Observable zu setzen bedeutet, dass eine fehlgeschlagene Anfrage ein leeres Array zurückgibt und der äußere Stream weiterfließt. Würde catchError in die äußere Pipe verschoben, beendete es die gesamte Suche nach dem ersten Fehler und bräche jeden folgenden Tastendruck. Die vier Flattening-Operatoren beantworten jeweils eine andere Nebenläufigkeitsfrage, und die falsche Wahl ist eine der häufigsten Ursachen für Race Conditions in Angular-Anwendungen.
switchMap bricht die vorherige innere Anfrage ab und behält nur die neueste (Typeahead-Suche). mergeMap führt jede innere Anfrage nebenläufig aus (unabhängige parallele Uploads). concatMap reiht Anfragen in strikter Reihenfolge auf (sequenzielle Schreibvorgänge, die sich nicht überschneiden dürfen). exhaustMap ignoriert neue Eingaben, bis die aktuelle abgeschlossen ist (Blockieren eines doppelt geklickten Absende-Buttons).
Diese Wahl richtig zu treffen, macht aus einem instabilen Feature ein vorhersagbares. Das SharpSkill-Modul zu RxJS-Operatoren trainiert diese Unterschiede mit bewerteten Fragen, die genau die Race Conditions reproduzieren, die jeder Operator verhindert.
Subjects und Multicasting: BehaviorSubject, ReplaySubject und Subject
Ein einfaches Observable ist Unicast: Jeder Subscriber löst eine frische Ausführung aus. Ein Subject ist zugleich Observable und Observer, was es zum Multicast macht. Diese Eigenschaft macht Subjects zum Standardweg, um einen leichtgewichtigen State-Store oder einen Event-Bus innerhalb eines Service aufzubauen.
Die drei Varianten unterscheiden sich darin, was sie späten Subscribern erneut ausspielen. Ein einfaches Subject gibt nichts aus der Vergangenheit aus, sodass ein Subscriber nur Werte sieht, die nach dem Abonnieren eintreffen. Ein BehaviorSubject speichert den aktuellen Wert und spielt ihn sofort erneut aus, weshalb es einen Initialwert benötigt. Ein ReplaySubject puffert eine konfigurierbare Anzahl vergangener Ausgaben und spielt sie alle erneut aus.
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class CartService {
// BehaviorSubject holds the latest value and replays it to new subscribers
private readonly itemsSubject = new BehaviorSubject<string[]>([]);
// expose a read-only stream, never the writable Subject itself
readonly items$ = this.itemsSubject.asObservable();
add(item: string): void {
const current = this.itemsSubject.value; // synchronous access to the last value
this.itemsSubject.next([...current, item]); // emit the next immutable state
}
}Zwei Gewohnheiten sind hier entscheidend. Erstens verhindert das Bereitstellen von asObservable() statt des Subjects, dass externer Code next() aufruft und Zustand durch die Hintertür verändert. Zweitens hält das Ausgeben einer neuen Array-Referenz statt einer In-Place-Mutation die Change Detection und Gleichheitsprüfungen vorhersagbar. Dieses Muster ist älter als Signals und funktioniert für geteilten, injizierbaren Zustand, den mehrere voneinander unabhängige Komponenten konsumieren, weiterhin gut.
Allerdings lässt sich ein BehaviorSubject, das rein dazu dient, einen einzelnen aktuellen Wert für das Template zu halten, heute oft besser als beschreibbares Signal ausdrücken, was das Abonnement und die asObservable()-Zeremonie entfällt. Das Subject bleibt die stärkere Wahl, wenn der Store seine Ausgaben zusätzlich transformieren, entprellen oder mit anderen Streams kombinieren muss, da diese Operatoren kein direktes Signal-Äquivalent haben. Fallweise zwischen beiden zu entscheiden, statt überall auf eines zurückzufallen, ist ein Zeichen von Souveränität, das Interviewer belohnen.
RxJS-Signals-Interop mit toSignal und toObservable
Das Interop-Paket liefert zwei Hauptfunktionen. toSignal wandelt ein Observable in ein schreibgeschütztes Signal um, das ein Template direkt konsumieren kann, und verwaltet den Lebenszyklus des Abonnements automatisch. toObservable macht das Umgekehrte und verwandelt ein Signal in ein Observable, sodass RxJS-Operatoren seine Änderungen verarbeiten können.
import { Component, signal, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { toSignal, toObservable } from '@angular/core/rxjs-interop';
import { switchMap } from 'rxjs/operators';
@Component({ selector: 'app-dashboard', template: `{{ user()?.name }}` })
export class DashboardComponent {
private http = inject(HttpClient);
// a Signal drives the query; toObservable turns each change into a stream event
readonly userId = signal(1);
private readonly user$ = toObservable(this.userId).pipe(
switchMap((id) => this.http.get<{ name: string }>(`/api/users/${id}`))
);
// toSignal subscribes immediately and unsubscribes on destroy, no manual teardown
readonly user = toSignal(this.user$, { initialValue: null });
}Die Option initialValue verdient Beachtung. Ohne sie gibt toSignal ein Signal zurück, das als der Wert oder undefined typisiert ist, weil noch nichts ausgegeben wurde. Die Übergabe von initialValue: null gibt dem Template einen definierten Anfangszustand und einen saubereren Typ. Für synchrone Quellen wie ein BehaviorSubject garantiert requireSync: true, dass beim ersten Lesen ein Wert verfügbar ist, und entfernt undefined vollständig aus dem Typ. Diese bidirektionale Brücke ist es, die einer Codebasis erlaubt, Signals schrittweise einzuführen, ohne jede bestehende Observable-Pipeline neu zu schreiben. Das begleitende Angular-Signals-Interviewmodul behandelt das Reaktivitätsmodell in der Tiefe, und der Überblick über die Angular-18-Signals-Features zeichnet nach, wie sich diese Primitive entwickelt haben.
Bereit für deine Angular-Interviews?
Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.
Observables mit rxResource zu Signal-Ressourcen überbrücken
Angular 20 hebt rxResource als deklarativen Weg hervor, asynchrone Daten aus einem Observable in signalbasierten Zustand zu laden. Es verfolgt Lade-, Fehler- und Auflösungsstatus als Signals, was den Großteil der manuellen Abonnement-Buchführung entfernt, die HTTP-Aufrufe früher erforderten.
import { Component, signal, inject } from '@angular/core';
import { rxResource } from '@angular/core/rxjs-interop';
import { HttpClient } from '@angular/common/http';
@Component({ selector: 'app-products', template: `` })
export class ProductsComponent {
private http = inject(HttpClient);
readonly category = signal('laptops');
// Angular 20 renamed the fields: request -> params and loader -> stream
readonly products = rxResource({
params: () => ({ category: this.category() }),
stream: ({ params }) =>
this.http.get<Product[]>(`/api/products?category=${params.category}`),
});
// products.value(), products.isLoading() and products.error() are all signals
}Die Umbenennung von request/loader in Angular 19 zu params/stream in Angular 20 ist ein häufiger Stolperstein, sodass das Nennen der aktuellen Feldnamen im Interview aktuelles Wissen signalisiert. Wenn sich das category-Signal ändert, bricht rxResource die vorherige Anfrage ab und startet einen neuen Stream, wodurch switchMap-Semantik gratis mitgeliefert wird. Die rxResource-API-Referenz dokumentiert den vollständigen Status-Lebenszyklus.
Memory Leaks mit takeUntilDestroyed vermeiden
Jedes manuelle subscribe(), das seine Komponente überlebt, verursacht ein Memory Leak und kann Callbacks gegen eine zerstörte View feuern. Die historische Lösung war ein takeUntil(this.destroy$)-Muster mit einem in ngOnDestroy abgeschlossenen Subject. Angular ersetzte diesen Boilerplate durch takeUntilDestroyed, einen Operator, der das Abonnement an den aktuellen Injection-Kontext oder eine explizite DestroyRef bindet.
import { Component, inject, DestroyRef } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { interval } from 'rxjs';
@Component({ selector: 'app-live-feed', template: `` })
export class LiveFeedComponent {
private destroyRef = inject(DestroyRef);
constructor() {
interval(1000)
// completes the subscription automatically when the component is destroyed
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((tick) => console.log('tick', tick));
}
}Innerhalb eines Konstruktors oder eines Feld-Initialisierers aufgerufen, benötigt takeUntilDestroyed() kein Argument, weil es die umgebende DestroyRef liest. An jeder anderen Stelle aufgerufen, etwa innerhalb einer Methode, erfordert es eine explizit übergebene DestroyRef, wie oben gezeigt. toSignal und rxResource zu bevorzugen vermeidet manuelle Abonnements vollständig, was der sauberste Weg ist, Leaks zu umgehen; wird ein rohes Abonnement wirklich benötigt, ist takeUntilDestroyed der korrekte Schutz.
takeUntilDestroyed() ohne Argument außerhalb eines Injection-Kontexts aufzurufen, wirft einen Laufzeitfehler. Ein Abonnement innerhalb eines Event-Handlers, eines setTimeout oder eines RxJS-Callbacks liegt außerhalb dieses Kontexts, sodass die DestroyRef früher erfasst (typischerweise als injiziertes Feld) und explizit übergeben werden muss. Das zu vergessen ist die häufigste Ursache des Fehlers "takeUntilDestroyed() can only be used within an injection context".
Angular-RxJS-Interviewfragen, die eine Wiederholung wert sind
Interviewer kreisen tendenziell um dieselben aussagekräftigen Themen. Diese knapp beantworten zu können, trennt Kandidaten, die RxJS eingesetzt haben, von jenen, die nur darüber gelesen haben.
- Hot versus Cold Observables. Ein Cold Observable startet seinen Producer pro Abonnement, sodass jeder Subscriber eine unabhängige Ausführung erhält (eine frische HTTP-Anfrage). Ein Hot Observable teilt einen Producer über Subscriber hinweg, was Subjects und
share()erzeugen. - switchMap versus mergeMap versus concatMap versus exhaustMap.
switchMapbricht das vorherige innere Observable ab (ideal für die Suche).mergeMapführt alle inneren Observables nebenläufig aus.concatMapreiht sie der Reihe nach auf.exhaustMapignoriert neue Eingaben, während eine läuft (ideal, um doppeltes Absenden von Formularen zu verhindern). - Wie man Memory Leaks verhindert.
toSignal,rxResourceoder dieasync-Pipe bevorzugen, die alle automatisch abbestellen; für manuelle AbonnementstakeUntilDestroyednutzen. - Wann man ein Observable in ein Signal umwandelt. Zu
toSignalgreifen, wenn ein Template einen Wert synchron benötigt und die Quelle asynchron ist, sodass die Change Detection den neuesten Wert ohneasync-Pipe lesen kann.
Bewertete Varianten dieser Fragen unter Zeitdruck durchzuarbeiten, ist der schnellste Weg, sie zu verinnerlichen. Der Angular-Technologie-Hub bündelt die Module zu RxJS, Signals und Change Detection, die direkt auf diese Fragen abbilden.
Fang an zu üben!
Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.
Fazit
RxJS und Signals sind Partner im modernen Angular-Stack, keine Rivalen. Die Erkenntnisse, die es sich lohnt, ins nächste Projekt oder Interview mitzunehmen:
- Signals für synchronen Komponentenzustand nutzen und Observables für asynchrone Ereignis-Pipelines, die Operatoren benötigen.
- Zu
switchMapgreifen, um veraltete Arbeit abzubrechen, zuexhaustMap, um Duplikate zu blockieren, undcatchErrorauf dem inneren Observable halten, damit der äußere Stream Fehler überlebt. - Subject-Zustand über
asObservable()bereitstellen und unveränderliche Werte ausgeben, um die Change Detection vorhersagbar zu halten. - Die beiden Modelle mit
toSignalundtoObservableüberbrücken undinitialValueoderrequireSyncfür saubere Typen übergeben. - Asynchrone Daten deklarativ mit
rxResourcein Angular 20 laden und dabei die Feldnamenparamsundstreambeachten. - Jedes verbleibende manuelle Abonnement mit
takeUntilDestroyedabsichern, um Leaks zu beseitigen.
Tags
Teilen
Verwandte Artikel

Angular 20 im Jahr 2026: Resource API, httpResource und Interviewfragen
Angular 20 führt die Resource API und httpResource als signalbasierte Alternativen zu manuellen HttpClient-Subscriptions ein. Dieser Leitfaden behandelt alle drei Resource-Varianten, Zod-Validierung und häufige Interviewfragen.

Angular @defer im Jahr 2026: Deklaratives Lazy Loading und Interview-Fragen
Umfassender Leitfaden zu Angular @defer-Bloecken: Trigger-Typen, Prefetching, SSR-Verhalten, inkrementelle Hydration, Performance-Patterns und die wichtigsten Interview-Fragen fuer Angular-Positionen.

Angular 19 Interviewfragen: Signals, SSR und unverzichtbare Konzepte
Die häufigsten Angular 19 Interviewfragen: Signals, inkrementelle Hydration, zoneless Change Detection und neue reaktive APIs mit Codebeispielen und erwarteten Antworten.