Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 4 - Best way of unsubscribing

Tags:

angular

rxjs

I am curious on how am I suppose to unsubscribe all my subscriptions. I knew about the takeWhile() and takeUntil(). I find the takeUntil() more usable for me.

as far as I understand, takeWhile() take effects after we get the data. then unsubscribe until the component is destroy.

Whats is the difference of using takeUntil() and not using it. just .unsubscribe()?

without using takeUntil()

ngOnInit() {
 this.subscriptions = this._membersService.getMembers().subscribe(data => 
 this.members = data)
}

ngOnDestroy() {
 this.subscriptions.unsubscribe();
}

using takeUntil

private destroyed$: Subject<{}> = new Subject();

ngOnInit() {
 this._membersService.getMembers().takeUntil(this.destroyed$).subscribe(data 
 => this.members = data)
}

ngOnDestroy() {
  this.destroyed$.next();
}

also how can I determine If I unsubscribe successfully?

like image 855
edizonv Avatar asked Oct 18 '17 01:10

edizonv


People also ask

What should be unsubscribe Angular?

Specifically, we must unsubscribe before Angular destroys the component. Failure to do so could create a memory leak. We unsubscribe from our Observable in the ngOnDestroy method.

Does Angular unsubscribe automatically?

They all have complete() method, so if you call that method, even if you had 100 subscriptions, they will all unsubscribed automatically.

Do I need to unsubscribe from Take 1?

Just keep in mind that take(1) still doesn't unsubscribe when component is being destroyed. The subscription remains active until first value is emitted no matter if component is active or destroyed.

Do we need to unsubscribe subject in Angular?

🎩 Automagically Unsubscribe in Angular As you probably know when you subscribe to an observable or event in JavaScript, you usually need to unsubscribe at a certain point to release memory in the system. Otherwise, you will have a memory leak. A memory leak occurs when a section of memory that is no longer being…


2 Answers

The main difference is the way of thinking... and the boilerplate.

Without takeUntil, when your file will grow in size and lines of code, you might end up with something like that:

private subscription1: Subscription;
private subscription2: Subscription;
private subscription3: Subscription;
private subscription4: Subscription;
private subscription5: Subscription;
private subscription6: Subscription;

ngOnInit() {
  this.subscription1 = this.service.method().subscribe(...);
  this.subscription2 = this.service.method().subscribe(...);
  this.subscription3 = this.service.method().subscribe(...);
  this.subscription4 = this.service.method().subscribe(...);
  this.subscription5 = this.service.method().subscribe(...);
  this.subscription6 = this.service.method().subscribe(...);
}

ngOnDestroy() {
  this.subscription1.unsubscribe();
  this.subscription2.unsubscribe();
  this.subscription3.unsubscribe();
  this.subscription4.unsubscribe();
  this.subscription5.unsubscribe();
  this.subscription6.unsubscribe();
}

Or, you might declare an array of subscriptions and push into it.

Both doesn't seem to be very handy and if you end up with many methods, containing subscriptions, you won't be able to see whether they're being unsubscribed or not if you don't scroll to the ngOnDestroy.

On the other hand, using a Subject is much more readable:

private onDestroy$ = new Subject<void>();

ngOnInit() {
  this.service.method().takeUntil(this.onDestroy$).subscribe(...);
  this.service.method().takeUntil(this.onDestroy$).subscribe(...);
  this.service.method().takeUntil(this.onDestroy$).subscribe(...);
  this.service.method().takeUntil(this.onDestroy$).subscribe(...);
  this.service.method().takeUntil(this.onDestroy$).subscribe(...);
  this.service.method().takeUntil(this.onDestroy$).subscribe(...);
}

ngOnDestroy() {
  this.onDestroy$.next();
  this.onDestroy$.complete();
}

Even if subscriptions are divided across the whole file, you can just check whether takeUntil(this.onDestroy$) is present or not.

It's also closer to the idea of Rxjs and dealing with streams.


Now, to make sure something is being unsubscribed, you can just use the third argument of subscribe:

this.service.method().takeUntil(this.onDestroy$).subscribe(
  onNext => ...,
  onError => ...,
  onComplete => console.log('stream has been completed')
);

If you don't like to put anything into the subscribe method, you could do that:

this.service.method().takeUntil(this.onDestroy$)
.do({
  complete => console.log('stream has been completed')
})
.subscribe();

If you want to go further down the subject, you should read this excellent article by Ben Lesh: https://medium.com/@benlesh/rxjs-dont-unsubscribe-6753ed4fda87

like image 70
maxime1992 Avatar answered Oct 25 '22 17:10

maxime1992


The recommended way is to use RxJS operators such as takeUntil() operator as is explained by @maxime1992, but takeUntil() isn't the only operator for the job you can use other RxJS operators as well for example takeWhile(), first(), elementAt(), etc. You can find a detailed explanation here.

like image 39
Yatharth Varshney Avatar answered Oct 25 '22 17:10

Yatharth Varshney