Skip to content

Observables

An Observable (from the RxJS library, which Angular uses extensively) represents a stream of values over time β€” unlike a Promise, which resolves exactly once, an Observable can emit zero, one, or many values, and can be transformed with operators (map, filter, debounceTime, etc.) before you subscribe. Nothing happens until you .subscribe() β€” Observables are β€œcold” (lazy) by default.

import { Subject, interval } from 'rxjs';
import { map, filter, debounceTime } from 'rxjs/operators';
const searchInput$ = new Subject<string>();
searchInput$
.pipe(
debounceTime(300), // wait for typing to pause
filter(term => term.length > 2), // ignore very short queries
map(term => term.toLowerCase()),
)
.subscribe(term => search(term));
searchInput$.next('a');
searchInput$.next('an');
searchInput$.next('angular'); // only this one triggers search(), after the 300ms pause
// Angular's own signals (16+) are a related-but-different reactive primitive
import { signal, computed } from '@angular/core';
const count = signal(0);
const doubled = computed(() => count() * 2);
count.set(5); // doubled() now returns 10

Manually subscribing to an Observable in a component and forgetting to unsubscribe in ngOnDestroy β€” the subscription (and anything it references) keeps running after the component is destroyed, causing a memory leak.

export class SearchComponent implements OnInit {
ngOnInit() {
this.searchService.results$.subscribe(results => {
this.results = results; // this callback keeps firing even after the component is gone!
});
}
}
// Fix: unsubscribe on destroy, or (better) let the async pipe manage it automatically
export class SearchComponent implements OnInit, OnDestroy {
private sub?: Subscription;
ngOnInit() {
this.sub = this.searchService.results$.subscribe(results => this.results = results);
}
ngOnDestroy() {
this.sub?.unsubscribe();
}
}
  1. What’s the key difference between an Observable and a Promise?

    AnswerA Promise resolves exactly once; an Observable can emit zero, one, or many values over time, and supports a large library of operators for transforming that stream before subscription.
  2. Why does manually subscribing without unsubscribing cause a memory leak?

    AnswerThe subscription (and everything its callback references, including the component instance) stays alive and keeps running even after the component is destroyed, since nothing ever told it to stop.
  3. What’s the easiest way to avoid manual subscription management in a template?

    AnswerUse the async pipe ({{ value$ | async }}) β€” it subscribes automatically when the template renders and unsubscribes automatically when the component is destroyed.