Angular uses RxJS as a backbone of the Angular application. RxJS uses the concept of Observables and Observers, where an Observable is a source of data and Observer is the one who use the data. Every time an Observable produces new values, it informs an Observer and the Observer handles those values inside subscribe operator. Dealing with Observables can be dangerous because there is the possibility of creating a memory leak. How’s that even possible?
Problem
Every time a component/directive is destroyed, all subscriptions to custom Observables still remain active.
Solution
Manually unsubscribe from all custom Observables when a component/directive gets destroyed. The best place to unsubscribe is inside functions that handle the OnDestroy lifecycle hook. Some subscriptions like router and http don’t need manual unsubscribe, for the rest of them there are various solutions:
- execute unsubscribe over the subscription object
- using takeUntil operator
- using async pipe
Unsubscribe
1export class UnsubscribeCardComponent implements OnInit, OnDestroy {
2 message: string;
3 subscription: Subscription;
4 constructor(private upperCaseService: UpperCaseService) {}
5
6 ngOnInit() {
7 this.subscription = this.upperCaseService.getUpperCaseMessage()
8 .subscribe((message: string) => this.message = message);
9 }
10
11 ngOnDestroy(): void {this.subscription.unsubscribe();}
12}
Subscription represents a disposable resource, it has an unsubscribe method that can be used to dispose the resource held by the subscription.
TakeUntil
1export class TakeUntilCardComponent implements OnInit, OnDestroy {
2 message: string;
3 private unsubscribe$ = new Subject();
4 constructor(private upperCaseService: UpperCaseService) {}
5
6 ngOnInit() {
7 this.upperCaseService.getUpperCaseMessage()
8 .takeUntil(this.unsubscribe$)
9 .subscribe((message: string) => this.message = message);
10 }
11
12 ngOnDestroy(): void {
13 this.unsubscribe$.next();
14 this.unsubscribe$.complete();
15 }
16}
TakeUntil takes a second Observable as an argument, it monitors the second Observable and discard subscription after it emits a value or terminates.
AsyncPipe
1export class AsyncPipeCardComponent implements OnInit {
2 messageSubscription: Observable<string>;
3 constructor(private upperCaseService: UpperCaseService) {}
4
5 ngOnInit() {
6 this.messageSubscription = this.upperCaseService.getUpperCaseMessage();
7 }
8}
1<h4 class="card-title">{{messageSubscription | async}}</h4>
The async pipe subscribes to an Observable and returns the latest value it has emitted. When a component is destroyed, the async pipe unsubscribes automatically.
Conclusion
When a component/directive is destroyed, all custom Observables need to be unsubscribed manually. Async pipe is a good solution, because it does everything automatically, but keep in mind that it can’t be used in all scenarios.
The RxJS lead developer Ben Lesh recommends the takeUntil approach. He explains his arguments in this article.
The sourcecode for the complete example can be found here.
The demo example can be found here.
More articles
fromMilos Brdar
Your job at codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
More articles in this subject area
Discover exciting further topics and let the codecentric world inspire you.
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Blog author
Milos Brdar
Do you still have questions? Just send me a message.
Do you still have questions? Just send me a message.