0

Is there any design pattern in angular 12 to cancel observable subscriptions?

Currently we are developing an angular app and found out that some of our components does not unsubscribe to the observable and hence it is causing memory leakage and some weird behavior in different pages. So instead of closing the subscriptions in each component using ngDestroy like for example below, is there a better way like a design pattern that can be reused across the app without changing existing behavior and minimal code as possible?


import {Component, OnInit, Output, EventEmitter, OnDestroy } from '@angular/core';  
import { HttpClient } from '@angular/common/http';  
import { Subscription } from 'rxjs';  
@Component({ … })  
export class ExampleComponent implements OnInit, OnDestroy {  
 data: any;  
 private subscription: Subscription;  
 API: string = 'https://jsonplaceholder.typicode.com/todos/1';  
  constructor (private http: HttpClient){}  
  ngOnInit() {  
   // Subscribed here  
    this.subscription.add( 
     this.http.get(this.API).subscribe(  
     res => {  
        this.data = res;  
     } ); 
   ) 
 }  
  ngOnDestroy() {  
   // Unsubscribed the subscription  
  this.subscription.unsubscribe();  
  }  
}
happytohelp
  • 305
  • 3
  • 14
  • The "clasic" is the first Option -the takeUntil(this.destroy$)- in this [SO](https://stackoverflow.com/questions/58428791/angular-rxjs-observable-takeuntil-vs-unsubscribe-with-a-subscription) – Eliseo Oct 25 '22 at 06:13

1 Answers1

2

I doubt that this code is causing a memory leakage in your application. HTTP calls return observables which will only emit one value and complete or emit an error. After this emission your subscription will automatically unsubscribe (see Do I have to unsubscribe from completed observable?).

This means that "ending" observables are in general not a problem causing a memory leak, but "never ending" observables are, e.g. when creating a Subject, but never calling complete(). In this way you have different options to unsubscribe (based on your needs):

  1. unsubscribe as described in your code sample
  2. use take operator to only take n values and afterwards complete
  3. use takeUntil operator to take values until another observable emits a value and afterwards complete
  4. use takeWhile to take values until a condition is met (be aware that this condition should at any point in time)
  5. best option: use a declarative pattern and don't subscribe to your observable in your Typescript code at all. Use async pipe to let angular handle the subscription and unsubscribe on component destruction.
Fabian Strathaus
  • 3,192
  • 1
  • 4
  • 26
  • the attached link is for java rxjs – happytohelp Oct 25 '22 at 15:41
  • You are correct. Here is a link referring to rxjs (same behavior): https://stackoverflow.com/questions/40452979/does-subject-complete-unsubscribe-all-listeners – Fabian Strathaus Oct 25 '22 at 15:43
  • but in the code, we are not using complete but using next – happytohelp Oct 25 '22 at 15:53
  • Well, not in the code you provided. As explained in my answer, the problem is not with completing Observables (like http calls), but with uncompleting ones (like subjects, where you can call `next()` on). – Fabian Strathaus Oct 25 '22 at 16:02
  • so please correct me, in this below example: ``` this.http.get('https://api.npms.io/v2/invalid-url').subscribe({ next: data => { this.totalAngularPackages = data.total; }, error: error => { this.errorMessage = error.message; console.error('There was an error!', error); } })``` does this mean the subsciption is a completing subscription? – happytohelp Oct 25 '22 at 17:14
  • Well, the subscription itself is not completing, but the observable will either complete or error out, which will then automatically call unsubscribe on all subscriptions. – Fabian Strathaus Oct 25 '22 at 21:22