Unsubscribe An Observable:
In Angular applications, it's always recommended to unsubscribe the observables to gain benefits like:
- Avoids Memory Leaks
- Aborting HTTP requests to avoid unwanted calls.
So in this demo, we will understand the case studies to unsubscribe an observable.
Memory Leaks:
Now let's implement observables code with memory leaks. So first let's create a service like 'test.service.ts' inside of initialize the 'BehaviourSubject' as below.
services/test.service.ts:
import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root', }) export class TestService { randNumberSub: BehaviorSubject<number> = new BehaviorSubject<number>( Math.random() ); }
- (Line: 8-10) Initialized 'BehaviorSubject' of type 'number'.
components/sample1.component.ts:
import { Component, OnDestroy, OnInit } from '@angular/core'; import { TestService } from 'src/app/services/test.service'; @Component({ templateUrl: 'sample1.component.html', }) export class Sample1Component implements OnInit { constructor(private testService: TestService) {} ngOnInit(): void { this.testService.randNumberSub.subscribe((data) => { console.log(`Sample1Component ==> RandomNumber: ${data}`);; }); } }
- (Line: 8) Injected our 'TestService'.
- (Line: 11-13) Listening for the 'BehaviorSubject' changes.
import { Component, OnInit } from '@angular/core'; import { TestService } from 'src/app/services/test.service'; @Component({ templateUrl: 'sample2.component.html', }) export class Sample2Component implements OnInit { constructor(private testService: TestService) {} ngOnInit(): void { this.testService.randNumberSub.subscribe((data) => { console.log(`Sample2Component ==> RandomNumber: ${data}`); }); } buttonTest() { this.testService.randNumberSub.next(100); } }
- (Line: 8) Injected the 'TestService'.
- (Line: 11-13) Listening for the 'BehaviorSubject' changes.
- (Line: 16-18) The method that updates data to our 'BehaviorSubject', this method will be registered as a click event for the UI button.
- Run the application, 'Home' route configured to 'Sample1.component'. So in the browser console, we can check the 'BehaviourSubject' logs data to the console.
- Now navigate to 'Sample2.Component', since here also we listening for 'BehaviorSubject' we can see console log here is well
- In 'Sample2.Component', we have a button that can update the data to our 'BehaviorSubject'. So now we click the button we can observe subscription the 'Sample1.component' also executes in spite of we currently on the 'Sample2.component'. This is called observables memory leak happened due to no unsubscribing them.
Unsubscribe Observable To Resolve Memory Leak:
Now let's update our code to unsubscribe the observable inside of the component.
components/sample1.component.ts:
import { Component, OnDestroy, OnInit } from '@angular/core'; import { Subscription } from 'rxjs'; import { TestService } from 'src/app/services/test.service'; @Component({ templateUrl: 'sample1.component.html', }) export class Sample1Component implements OnInit, OnDestroy { sampl1sub?: Subscription; constructor(private testService: TestService) {} ngOnInit(): void { this.sampl1sub = this.testService.randNumberSub.subscribe((data) => { console.log(`Sample1Component ==> RandomNumber: ${data}`); }); } ngOnDestroy(): void { if (this.sampl1sub) { this.sampl1sub.unsubscribe(); } } }
- (Line: 9) Added a new 'Subscription' variable like 'sampl1sub'.
- (Line: 12) Assigning our 'BehaviorSubject' to the 'Subscription' variable.
- (Line: 16-20) finally calling 'unsubscribe' in the 'ngOnDestroy' method.
import { Component, OnDestroy, OnInit } from '@angular/core'; import { Subscription } from 'rxjs'; import { TestService } from 'src/app/services/test.service'; @Component({ templateUrl: 'sample2.component.html', }) export class Sample2Component implements OnInit, OnDestroy { sample2sub?: Subscription; constructor(private testService: TestService) {} ngOnInit(): void { this.sample2sub = this.testService.randNumberSub.subscribe((data) => { console.log(`Sample2Component ==> RandomNumber: ${data}`); }); } ngOnDestroy(): void { if (this.sample2sub) { this.sample2sub.unsubscribe(); } } buttonTest() { this.testService.randNumberSub.next(100); } }
- (Line: 9) Added a new 'Subscription' variable like 'sample2sub'.
- (Line: 13) Assigning our 'BehaviorSubject' to the 'Subscription' variable.
- (Line: 17-21) finally calling 'unsubscribe' in the 'ngOnDestroy' method.
Abort HTTP Request To Avoid Unwanted calls:
Now for suppose if we won't unsubscribe HTTP request observable, then some cases like when user shifting between components and component had HTTP request they still execute if we navigate to other components.
So let's go through this case study and later we will fix it.
services/test.service.ts:
getAlbums() { return this.http.get("https://jsonplaceholder.typicode.com/albums"); }
- Add some API call logic in our 'test.service.ts'
components/apicall.component.ts
import { Component, OnInit } from '@angular/core'; import { TestService } from 'src/app/services/test.service'; @Component({ selector: 'apicall', templateUrl: 'apicall.component.html', }) export class ApiCallComponent implements OnInit { constructor(private testService: TestService) {} ngOnInit(): void { this.testService.getAlbums().subscribe(data => { console.log(data); }) } }
- (Line: 11-13) Invoking the API call.
So to avoid the unwanted API call's on navigating to some other page, we just need to unsubscribe this HTTP request as well.
components/apicall.component.ts:(Use Unsubscribe)
import { Component, OnDestroy, OnInit } from '@angular/core'; import { Subscription } from 'rxjs'; import { TestService } from 'src/app/services/test.service'; @Component({ selector: 'apicall', templateUrl: 'apicall.component.html', }) export class ApiCallComponent implements OnInit, OnDestroy { apicallSub?:Subscription; constructor(private testService: TestService) {} ngOnInit(): void { this.apicallSub = this.testService.getAlbums().subscribe(data => { console.log(data); }) } ngOnDestroy():void{ if(this.apicallSub){ this.apicallSub.unsubscribe(); } } }
- (Line: 10) Added a new 'Subscription' API like 'apicallsub'.
- (Line: 13) Assigning the HttpRequest observable to our 'apicallsub' variable.
- (Line: 17-21) Finally unsubscribing the HttpRequest in the 'ngOnDestroy' method.
Support Me!
Buy Me A Coffee
PayPal Me
Video Session:
Wrapping Up:
Hopefully, I think this article delivered some useful information on unsubscribing an observable in angular application. I love to have your feedback, suggestions, and better techniques in the comment section below.
Nice tutorial. Use clear examples to prove why we need unsubscribe observable.
ReplyDeleteExcellent tutorial
ReplyDeleteNice tutorial. Also we can use Async pipe in component
ReplyDeleteExcellent !! Thanks !
ReplyDelete