When using web services, when is the best time to unsubscribe? In my code I have been doing this
tempFunction() {
const temp = this.myService.getById(id).sub
The answer is: Unsubscribe when you are done with the subscription. If it needs to be active for the entire life of your component, then unsubscribing in ngOnDestroy
is appropriate. If you only need one output from the observable, then unsubscribing in the .subscribe()
callback makes sense. If some other condition in your app can mean the subscription is no longer needed at some arbitrary time, feel free to unsubscribe whenever needed.
The only rule is "Don't forget to unsubscribe." There's no hard rule about when to do it.
You don't need to unsubscribe from a simple web request like you have. They only fire once and will take care of the unsubscribe for you. Here is a SO question that discusses this very topic and why it is unnecessary.
As a general topic of how to unsubscribe, the best approach tends to be using this pattern of using takeUntil
. This allows you to ensure that everything is cleaned up when your component is destroyed in the cleanest way possible (without having to hold onto multiple subscriptions and calling unsubscribe
on each of them).
import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/takeUntil';
@Component({ ... })
export class ExampleComponent implements OnInit, OnDestroy {
destroy$: Subject<boolean> = new Subject<boolean>();
ngOnInit() {
this.someMethodThatReturnsObservable(...)
.takeUntil(this.destroy$)
.subscribe(...);
this.someOtherMethodThatReturnsObservable(...)
.takeUntil(this.destroy$)
.subscribe(...);
}
ngOnDestroy() {
this.destroy$.next(true);
// Now let's also unsubscribe from the subject itself:
this.destroy$.unsubscribe();
}
}
When you unsubscribe depends on what the subscription is and how you actually use it. In your example, you are calling .unsubscribe
when the Observable completes. You don't need to do this since when the Observable has completed it will no longer emit. Instead you need to unsubscribe if the Observable will continue to emit after you may not need it anymore e.g. when navigating away from your component. That is why you see ngOnDestroy
used for disposing of subscriptions.
Generally you want to avoid calling .unsubscribe
. See: https://medium.com/@benlesh/rxjs-dont-unsubscribe-6753ed4fda87
There are other ways to handle subscriptions such as using the take
methods. Angular also has the very powerful async pipe that allows you to use Observables in templates and handles unsubscribing for you.
Just to recap with some examples:
// No need to unsubscribe here. Http Observables only emit once
this.serviceUsingHttp.get().subscribe(useResponse);
// Allows you to call `.unsubscribe` in case the subscription wasn't created properly
events = new Subscription();
ngOnInit() {
this.events = fromEvent(document, 'someEvent').subscribe(useEvent);
}
ngOnDestroy() {
this.events.unsubscribe();
}
destroyed$ = new Subject();
ngOnInit() {
fromEvent(document, 'resize').pipe(takeUntil(this.destroyed$)).subscribe(useResize);
fromEvent(document, 'scroll').pipe(takeUntil(this.destroyed$)).subscribe(useScroll);
fromEvent(document, 'change').pipe(takeUntil(this.destroyed$)).subscribe(useChange);
}
ngOnDestroy() {
// Complete all of the event observables at once.
this.destroyed$.next(true);
this.destroyed$.complete();
}