Reputation: 337
I have a large application built on Angular 7. I want to implement something which will unsubscribe the RxJs subscribers if developer has forgotten to unsubscribe in ngOnDestroy. This is to ensure no memory leak in application.
Is it possible with Guards? When the route changes, the Guard will check which component was last loaded and unsubscribe its subscribers?
Upvotes: 0
Views: 485
Reputation: 1291
The recommended way to do this is to use the takeUntil
operator together with ngOnDestroy
. For example:
import { Component, OnDestroy, OnInit } from '@angular/core';
// RxJs 6.x+ import paths
import { filter, startWith, takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { BookService } from '../books.service';
@Component({
selector: 'app-books',
templateUrl: './books.component.html'
})
export class BooksComponent implements OnDestroy, OnInit {
private ngUnsubscribe = new Subject<void>();
constructor(private booksService: BookService) { }
ngOnInit() {
this.booksService.getBooks()
.pipe(
startWith([]),
filter(books => books.length > 0),
takeUntil(this.ngUnsubscribe)
)
.subscribe(books => console.log(books));
this.booksService.getArchivedBooks()
.pipe(takeUntil(this.ngUnsubscribe))
.subscribe(archivedBooks => console.log(archivedBooks));
}
ngOnDestroy() {
this.ngUnsubscribe.next();
this.ngUnsubscribe.complete();
}
}
For more details, see this answer: Angular/RxJS When should I unsubscribe from `Subscription`
You might also be interested in these tslint rules. They will ensure some level of correct use of RxJS.
Upvotes: 1
Reputation: 51
@Injectable()
export class autoUnsubscribe {
subscriptions_: any[] = []
get subscriptions(): Subscription[] {
return this.subscriptions_
}
set subscriptions(v: any) {
this.subscriptions_.push(v)
}
ngOnDestroy(): void {
this.subscriptions.forEach((s) => {
s.unsubscribe()
})
}
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent extends autoUnsubscribe {
title = 'app';
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent extends autoUnsubscribe implements OnInit{
title = 'app';
ngOnInit() {
this.subscriptions=interval(2000).subscribe(console.log)
}
}
Upvotes: 0
Reputation: 12480
Is it possible with Guards? When the route changes, the Guard will check which component was last loaded and unsubscribe its subscribers?
Unfortunately not out of the box. And the reason is it would be hard to discern which list of subscriptions you should be unsubscribing from. For example, it could be any of these :
subscriptions : Subscription[]
subscriptions : any[]
subscriptions : any
Or even subscriptions inside a service that you want to unsubscribe.
However there are libraries that will do some of this for you (For example : https://tutorialsforangular.com/2020/12/14/auto-unsubscribing-from-observables-on-ngdestroy/). Unfortunately they still require either an attribute on the component, and/or some conventions to be used that your subscriptions array is always named the same.
It may also be possible (Since it's open source), to take a dive into the code and be able to apply it to a routeguard etc.
Upvotes: 1
Reputation: 196
The easiest way i can think of is to use AsyncPipe on your application
This way angular will unsubscribe the observable when the component is destroy
Ref: https://angular.io/api/common/AsyncPipe
Upvotes: 2