0

Since the ngOnInit is called only once in app's life, when I make a subscription to an observable in ngOnInit, is it still necessary to unsubscribe?

Is it possible for the app to create memory leak for the browser after the app/tab is closed?

techguy2000
  • 4,861
  • 6
  • 32
  • 48
  • After the tab/browser is closed? No. However, there are observables that keeps emitting data until you explicitly call unsubscribe or it errors. – nll_ptr Nov 08 '19 at 01:28
  • 1
    Possible duplicate of [Angular/RxJs When should I unsubscribe from \`Subscription\`](https://stackoverflow.com/questions/38008334/angular-rxjs-when-should-i-unsubscribe-from-subscription) – wentjun Nov 08 '19 at 02:19
  • am i missing something? why do people think this question is related to other random component subscription? i am talking about the app root. the only time you unsubscribe is when the app is closed. and if the app is closed, do we still care about memory leak? – techguy2000 Nov 08 '19 at 03:43
  • Have a read of my pattern for Angular state management here https://medium.com/@adrianbrand/angular-state-management-with-rxcache-468a865fc3fb – Adrian Brand Nov 08 '19 at 04:10
  • In most cases you shouldn't have to unsubscribe as described in #1 here https://medium.com/angular-in-depth/the-best-way-to-unsubscribe-rxjs-observable-in-the-angular-applications-d8f9aa42f6a0 . But might as well unsubscribe to guard against any edge cases... – techguy2000 Dec 31 '19 at 22:09

3 Answers3

2

The Short answers are:

1) Always

2) Yes

This article describes very well why we should unsubscribe from all observables, and how to do it in an effective way in angular.

If you are Subscribing on the ngOnInit function you should be unsubscribing via ngOnDestroy.

I usually create an unsubscribe Subject, and call next() on it on ngOnDestroy. I would have all my subscriptions with a takeUntil(unsubscribe).

This is what I mean:

unsubscribe = new Subject();

(...)

subscribeTo() {
   this.myService.getAll().pipe(
      takeUntil(this.unsubscribe),
    ).subscribe(data => this.localData = data);
}


ngOnDestroy() {
    this.unsubscribe.next();
    this.unsubscribe.complete();
  }
The Fabio
  • 5,369
  • 1
  • 25
  • 55
0

My answer is YES.

If this happen only one time in the OnInit lifecycle then you use take(1) is enough.

Example:

ngOnInit() {
   this.observableData$ = this.myService.getAll().pipe(take(1));
}

The benefits are:

  1. no unsubscribe
  2. no ngOnDestroy
  3. less code, less bug

However, I suggested you another way to handle data by reactive programming in this article. Because subscribe to get data is not right. We just use subscribe to do callback for another stuff (not data).

Hoang Subin
  • 6,610
  • 6
  • 37
  • 56
  • take is for handling emission. take(1) means you care about the first emission only. but i am interested in all emissions. my point is, when the app/browser tab is closed, is the browser still listening to the emissions? the app certainly doesn't care about memory leak when it's closed... – techguy2000 Nov 08 '19 at 03:40
  • I think it depends on the case. `take(1)` in case of call API to get data. In case of `subscribe` the form change or other things then you can use `takeUntil`. YES. But what if you do not close the tab? – Hoang Subin Nov 08 '19 at 03:44
  • if you don't close the tab then ngOnDestroy won't be called – techguy2000 Nov 08 '19 at 03:50
  • Yes. But in case of `take(1)` we do not need wait for `OnDestroy`. In case of `takeUntil` then need wait `OnDestroy` I sure that your site is not only have one page right? Because in my opinion, if your app have only one or two pages, you do not need to handle this one. – Hoang Subin Nov 08 '19 at 03:57
  • 1
    take(1) will not be unsubscribed if the observable has not emitted yet and you have an orphaned subscription. Use takeUntil. – Adrian Brand Nov 08 '19 at 04:06
0

I personally never subscribe an use the async pipe to manage subscriptions for me.

data$ = this.service.getData();

and in the template

<ng-conatainer *ngIf="data$ | async as data">
  {{ data | json }}
</ng-conatainer>

No need for any subscriptions.

Adrian Brand
  • 20,384
  • 4
  • 39
  • 60