Avoiding a Memory Leak in Angular


gif

Hey kids! I've been hard at work trying to get the hang of this Angular thing ... so far, it's slow but it's going! I'm happy to have a few things to share with you :)




One thing I learned while watching videos by Deborah Kurata is that when you subscribe to an API call, you should definitely use Rxjs. She explains that it can keep your site from having accidental memory leaks.


Leaky Angular isn't what we want .........


gif

SO!! That means, I had to figure out how to update my subscribe function to Rxjs.


.......and that was a chore. I had to bribe two coworkers to help me figure it out ... I'm pretty sure I owe them money now lol I'm still not sure why it was so difficult to find an example that worked for my specific situation, but I digress.


Ok, so how do we do it?


We have created an API service in api.service.ts to get Country data from a generic feed. This service is pointing to a separate API ready to accept a request.


 

NOTE: If you aren't sure how to create this service, follow along the official Angular Hero tutorial here.


 

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class ApiService {

  constructor(private http: HttpClient) { }

    getCountryData() {
    return this.http.get('https://localhost:44371/api/CountryData');

  }
}

Next, we hook up the original API subscribe in the GetData.component.ts file

export class GetDataComponent implements OnInit {

  constructor(private api: ApiService) { }

  ngOnInit(): void {
    this.api.getCountryData().subscribe((datalist) => {
      this.countryDetails = datalist;
    });
	}
}

We know this subscribe works.


Now, we need to update the subscribe to use Rxjs.


Go to https://rxjs.dev/guide/installation and follow the instructions to install Rxjs into your ClientApp folder using your terminal window.


cd into the ClientApp folder, then add the following command:



Fabulous! Now you have Rxjs installed and you can import it.


First, we need to change our HttpClient request into an Observable object in the api.service.ts file. I have bolded the changes we need to make.


import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class ApiService {

  constructor(private http: HttpClient) { }

  getCountryData(): Observable<any[]> {

    return this.http.get<any[]('https://localhost:44374/api/CountryData'); 
  }
}

Great! Now, we need to update the subscription part of things n the GetData.component.ts file. Again, the changes are bolded.


import { Component, OnInit, Input } from '@angular/core';
import { ApiService } from '../api.service';
import { tap } from 'rxjs/operators';
import { Subject } from 'rxjs';

export class GetDataComponent implements OnInit {

  countryDetails: any[] = [];
  dtTrigger: Subject<any> = new Subject<any>();
  
  constructor(private api: ApiService) { }

  ngOnInit(): void {
        this.api.getcountryDetails().pipe(
      tap(data => console.log("Items recieved:" + data.length))

    ).subscribe(data => {
      console.log("Started subscribing");
      this.countryDetails = data;
      this.dtTrigger.next();
    });
  }

  ngOnDestroy(): void {
    // Do not forget to unsubscribe the event
    this.dtTrigger.unsubscribe();
}
}

Ok awesome, so what does all this code do?


  • Observable - this is the object we want to capture the request result with. We want this to be of type <any[]> so it can consume any json list returned by the feed. We will parse that data later using the data model we create.


  • pipe - A pipe links operations together. So, you can string together multiple functions and they are executed in order. Think of it as similar to a LINQ operator.


  • subscribe - this produces a result. To get data, you must request it.


  • tap - allows logging


  • Subject - allows multicasting. so if we add new subscriptions, the single subject can handle multiple subscriptions. This also allows us to unsubscribe.


Learning: Is Fun?


The Bottom Line:


The unsubscribe is the important part. This allows us to cut out any potential memory leaks. once the data is returned from the subscription, the connection is terminated using the unsubscribe.


This is a very elementary approach to the power of Rxjs and Observables and what they can do. I am still learning so I may have gotten some things wrong here. If I did, I will do my best to come back and correct any mistakes I made. Please let me know in the comments if I don't make a needed correction!


Cheers!!















8 views0 comments