Unsubscribing from Observable in a non-Component/Directive class

Viewed 1558

I've read tons of posts on unsubscribing from Observables in Angular and all of them mention the need to do so in components/directives only.

So my question is:

Do we need to unsubscribe from Observables in a non-component/directive class e.g. in a service or basically any other class that contains subscriptions to Observables?

2 Answers

You unsubscribe in components because when you remove them from DOM (eg. with *ngIf or whatever) RxJS chains would hold references to observers you created there. Thus introducing memory leaks.

In general you don't have to unsubscribe in services because they exist during the entire lifetime of your application.

However, in Angular you can create a component that for example provides a different service instance only to its descendants (this means you might have multiple instances of the same service class in your app). In such case you should unsubscribe manually (probably when destroying the component that defined them).

I think it's important to call out why unsubscribing is important. It's never necessary to unsubscribe from a stream, but there can be advantages to performance and in some cases it's important to unsubscribe as part of the feature.

It's also important to say that unsubscribing is the responsibility of the consumer. The only way for a stream to "force" a consumer to unsubscribe is by completing or erroring.

In Angular services, if you end up subscribing to a stream, unsubscribing is good practice unless you have a good reason to keep listening. Here's an (contrived) example:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

@Injectable()
export class MyService {
  constructor( private session: Session ) { }

  isLoggedIn(): Observable<boolean> {

    return Observable.create( observer => {
      const innerSubscription = this.session.subscribe( session => {
        if ( session.user.isLoggedIn ) {
          observer.next( true );
        }
        observer.next( false );
      });

      return function unsubscribe() {
        innerSubscription.unsubscribe(); // this "cleans up" our subscription.
      };
    });

  }
}

There are other, better, ways to write this code, it's just an example. So in this case, we have a non Component/Directive that subscribes to a session. Every time the session changes, we look to see if the user is logged in and notify our listeners if they are/aren't. If everyone unsubscribes from us, we would still be listening to this.session unless we (the service) explicitly unsubscribe.

Related