0

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).subscribe(
        response => this.model = response,
        error => console.error(error),
        final => temp.unsubscribe() // unsubscribe here
    );
}

But everywhere else, I have seen this

temp: any;

tempFunction() {
    temp = this.myService.getById(id).subscribe(
        response => this.model = response,
        error => console.error(error),
        final => {}
    );
}

ngOnDestroy() {
    this.temp.unsubscribe(); // vs unsubscribe here
}

Is there a functional difference in how I am unsubscribing vs how everyone else is unsubscribing?

rhavelka
  • 2,283
  • 3
  • 22
  • 36
  • 2
    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. – Daniel W Strimpel Apr 12 '18 at 16:32

3 Answers3

2

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();
    }
}
Daniel W Strimpel
  • 8,190
  • 2
  • 28
  • 38
  • 1
    Ok, that makes sense, I just found a few articles [here](https://medium.com/thecodecampus-knowledge/the-easiest-way-to-unsubscribe-from-observables-in-angular-5abde80a5ae3) and [here](http://brianflove.com/2016/12/11/anguar-2-unsubscribe-observables/) where they seem to unsubscribe from everything – rhavelka Apr 12 '18 at 16:50
1

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.

JC Ford
  • 6,946
  • 3
  • 25
  • 34
0

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();
}
Explosion Pills
  • 188,624
  • 52
  • 326
  • 405