5

Why We Have To Unsubscribe An Observable In An Angular Application?

 3 years ago
source link: https://www.learmoreseekmore.com/2021/11/why-we-have-to-unsubscribe-an-observable-in-angular-application.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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:
  1. import { Injectable } from '@angular/core';
  2. import { BehaviorSubject } from 'rxjs';
  3. @Injectable({
  4. providedIn: 'root',
  5. export class TestService {
  6. randNumberSub: BehaviorSubject<number> = new BehaviorSubject<number>(
  7. Math.random()
  • (Line: 8-10) Initialized 'BehaviorSubject' of type 'number'.

Now let's create components like 'sample1.component.ts' and 'sample2.component.ts' these will consume the 'test.service.ts' and listen for the 'BehaviorSubject' changes.

components/sample1.component.ts:
  1. import { Component, OnDestroy, OnInit } from '@angular/core';
  2. import { TestService } from 'src/app/services/test.service';
  3. @Component({
  4. templateUrl: 'sample1.component.html',
  5. export class Sample1Component implements OnInit {
  6. constructor(private testService: TestService) {}
  7. ngOnInit(): void {
  8. this.testService.randNumberSub.subscribe((data) => {
  9. console.log(`Sample1Component ==> RandomNumber: ${data}`);;
  • (Line: 8) Injected our 'TestService'.
  • (Line: 11-13) Listening for the 'BehaviorSubject' changes.
components/sample2.components.ts:
  1. import { Component, OnInit } from '@angular/core';
  2. import { TestService } from 'src/app/services/test.service';
  3. @Component({
  4. templateUrl: 'sample2.component.html',
  5. export class Sample2Component implements OnInit {
  6. constructor(private testService: TestService) {}
  7. ngOnInit(): void {
  8. this.testService.randNumberSub.subscribe((data) => {
  9. console.log(`Sample2Component ==> RandomNumber: ${data}`);
  10. buttonTest() {
  11. 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.
Now to observe memory leaks follow the below steps:
  • 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:
  1. import { Component, OnDestroy, OnInit } from '@angular/core';
  2. import { Subscription } from 'rxjs';
  3. import { TestService } from 'src/app/services/test.service';
  4. @Component({
  5. templateUrl: 'sample1.component.html',
  6. export class Sample1Component implements OnInit, OnDestroy {
  7. sampl1sub?: Subscription;
  8. constructor(private testService: TestService) {}
  9. ngOnInit(): void {
  10. this.sampl1sub = this.testService.randNumberSub.subscribe((data) => {
  11. console.log(`Sample1Component ==> RandomNumber: ${data}`);
  12. ngOnDestroy(): void {
  13. if (this.sampl1sub) {
  14. 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.
components/sample2.component.ts:
  1. import { Component, OnDestroy, OnInit } from '@angular/core';
  2. import { Subscription } from 'rxjs';
  3. import { TestService } from 'src/app/services/test.service';
  4. @Component({
  5. templateUrl: 'sample2.component.html',
  6. export class Sample2Component implements OnInit, OnDestroy {
  7. sample2sub?: Subscription;
  8. constructor(private testService: TestService) {}
  9. ngOnInit(): void {
  10. this.sample2sub = this.testService.randNumberSub.subscribe((data) => {
  11. console.log(`Sample2Component ==> RandomNumber: ${data}`);
  12. ngOnDestroy(): void {
  13. if (this.sample2sub) {
  14. this.sample2sub.unsubscribe();
  15. buttonTest() {
  16. 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.

Now if we test again we can observe memory leaks won't appear again.

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:
  1. getAlbums() {
  2. return this.http.get("https://jsonplaceholder.typicode.com/albums");
  • Add some API call logic in our 'test.service.ts'
Now let's create new components like 'components/apicall.component.ts'
components/apicall.component.ts
  1. import { Component, OnInit } from '@angular/core';
  2. import { TestService } from 'src/app/services/test.service';
  3. @Component({
  4. selector: 'apicall',
  5. templateUrl: 'apicall.component.html',
  6. export class ApiCallComponent implements OnInit {
  7. constructor(private testService: TestService) {}
  8. ngOnInit(): void {
  9. this.testService.getAlbums().subscribe(data => {
  10. console.log(data);
  • (Line: 11-13) Invoking the API call.
Now run the application, visit the 'apicall.component', and before receiving the API response, just navigate to other components but we can observe that API call's still get executed as below.
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)
  1. import { Component, OnDestroy, OnInit } from '@angular/core';
  2. import { Subscription } from 'rxjs';
  3. import { TestService } from 'src/app/services/test.service';
  4. @Component({
  5. selector: 'apicall',
  6. templateUrl: 'apicall.component.html',
  7. export class ApiCallComponent implements OnInit, OnDestroy {
  8. apicallSub?:Subscription;
  9. constructor(private testService: TestService) {}
  10. ngOnInit(): void {
  11. this.apicallSub = this.testService.getAlbums().subscribe(data => {
  12. console.log(data);
  13. ngOnDestroy():void{
  14. if(this.apicallSub){
  15. 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.
Now if we test, our unwanted calls get aborted like below.

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.

Follow Me:


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK