Angular rxjs: Please Always Unsubscribe()

One of the finest library Angular 2.x+ featured is rxjs i.e reactive programming which kicks of it’s duty as soon as you subscribe() to it.

In this article, we will learn how to unsubscribe from an observable stream following this three points.

  1. Why you need to unsubscribe.
  2. When you should unsubscribe.
  3. How you unsubscribe.

Why you need to unsubscribe.

Reactive-Extensions for JavaScript (or RxJS) introduces the concept of Observables to Angular. If you have been used to version 1 of Angular then you are likely comfortable with Promises. And, while you might think an Observable is just like a Promise you might be surprised (as I was) to learn that they are in fact very different.

First, Promises are eager and are executed immediately. Observables are not eager and are only executed when subscribed to.

Second, Promises are asynchronous. Observables can be either synchronous or asynchronous.

Third, Promises are expected to return only a single value (like a function). Observables can return zero, one or more (infinitely) values.

Let me get to the point. A subscription is created when we subscribe() to an observable. And it is important that we unsubscribe from any subscriptions that we create in our Angular components to avoid memory leaks.

When you likely should unsubscribe

when do we unsubscribe? In most instances the best time to unsubscribe is when your component is destroyed. Angular introduced the the ngOnDestroy() lifecycle method:

ngOnDestroy(): Cleanup just before Angular destroys the directive/component. Unsubscribe observables and detach event handlers to avoid memory leaks.

AsyncPipe

Before we go any farther; if you are using observable streams via the AsyncPipe then you do not need to worry about unsubscribing. The async pipe will take care of subscribing and unsubscribing for you.

How you unsubscribe.

You can unsubscribe anytime from observable stream anytime by using the unsubscribe() method.

The unsubscribe methods simply store the subscription and invoke the unsubscribe() method when the component is destroyed.

unsubscribe()

First, let’s assume we have a UserService class with an authenticate() method:

@Injectable()
export class UserService {
  public authenticate(email: string, password: string): Observable<User> {
//code omitted
}
}

In our component we first import the OnDestroy class from @angular/core as well as the ISubscription interface from rxjs:

import { OnDestroy } from "@angular/core";
import { ISubscription } from "rxjs/Subscription";

Next, we implement the abstract class and declare a variable to store a reference to our subscription:

export class MyComponent implements OnDestroy {
  private subscription: ISubscription;
}

Next, let’s subscribe to the observable returned from the UserService.authenticate() method. In this example I have a method that is invoked when a login form is submitted:

public onSubmit() {
//authenticate the user via the UserService
this.subscription = this.userService.authenticate(email, password).subscribe(user => {
this.user = user;
});
}

Finally, when our component is destroyed we unsubscribe:

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

If we are subscribing to multiple subscriptions we do not need to use a collection to store all of the subscription instances. Rather, a subscription can have child subscriptions. Simply invoke the add()method to add additional child subscriptions. This is helpful, as all child subscriptions will be unsubscibed when we unsubscribe() the parent subscription.

Let’s add an additional subscription:

getUser(id: string) {
const subscription = this.userService.get(id)
.subscribe(user => {
this.user = user;
});
this.subscription.add(subscription);
}

In the code above we are getting an additional user by their id value from the REST API, and we are subscribing to the observable that is returned from the get() method. We simply add() this new subscription to our existing subscription object. Then, invoke the unsubscribe() method, just like we did before:

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

Now, both the primary subscription (to the authenticate() method) is unsubscribed, as well as the child subscription (to the get() method).

Which method?

The question you might be asking yourself at this point is:

Which method should I use to unsubscribe?

First, I would recommend that you use the async pipe. It makes sense to abstract this away and to let the Angular framework handle the subscriptions for you.

If using the async pipe is not a good solution for your needs, then I would recommend you to use the unsubscribe() method as shown above, whichever is more convenient for you and your application.

Thanks for your time, don’t forget to keep clapping and please don’t unsubscribe() form my articles :)