Should I unsubscribe from Angular 2 Http Observables?

Do I need to unsubscribe from an Observable?

When using RxJS with Angular 2 you can often avoid calling .subscribe() on Observables because the framework does a lot for you. Look at the async pipe for example, which both subscribes and unsubscribes for you.

But what about when you manually call .subscribe() on some Observable in your component?

I asked myself this same question and did some research to find a reasonable answer.

Finite and infinite

Observables produce/emit values over time but in answering this question it can be helpful to categorize Observables into two groups: finite values and infinite values.

Finite Observables are ones that will stop emitting values at some point before the application ends, whereas infinite ones will not stop until the end of time (when you close your browser tab).

Clicks and requests

Listening for events

Javascript event listeners, like listener to mouse clicks, are an allocated resource (read memory) in the web world. We need to manage these resources carefully so as not to create memory leaks. If you create one of these listeners it won’t just go away after a minute, an hour, or ever as long as the application is running. Clicks can continue to be captured and your function will be called. This make sense because the emitting of the mouse click event is totally up to the user and the user will decide when they stop clicking, not the app.

Let’s place DOM event listeners into the infinite value Observables group.

If we register this event listener in our component by calling something like Observable.fromEvent() and then the user navigates away or somehow causes the component to be destroyed, the listener will still be there. Javascript doesn’t know that just because our component is no longer there we do not care about the events. When the user clicks the even will still be emitted but nothing will respond.

If the component is recreated a new event listener will be created by the call to  Observable.fromEvent(). These event listeners will continue to pile up and eat up memory.

We can stop this nasty scenario by calling .unsubscribe() on the subscription returned by the Observable. This call can be made anywhere but a convenient place for it is in the ngOnDestroy() method of your component. That way you know when the component is destroyed the resources allocated for the event listener will also be freed and this clean up will not be dependent on any of your compoenent’s logic or state.

What about http requests?

Http requests are a different type of thing from an event listener. By their very nature they are finite. You make one request and get one response. But did you know that XMLHttpRequests also use event listeners?!

From: MDN

With $http requests and Promises in Angular 1 you know that your .finally() method will always be called but you never worried about un-promising or cleaning up that event listener. That’s because the framework handled it for you.

Likewise with Observables and RxJS everything is handled for you as long as the stream of values completes.

This is the key different between finite value Observables and infinite valued ones. In Angular 2, http requests will always return one value and then complete. They will always complete, even if you get a 404 or something else with the request fails, just like your .finally() method was always called with Promises in Angular 1. When an RxJS Observable completes it cleans itself and all of its allocated resources up.

Even if you navigate away from the component before the http response arrives and the component is destroyed the Observable will still complete and clean up there just won’t be anyone around to respond to it (I could probably say something about a tree in the forest here).

You do not need to .unsubscribe() from http requests.

Another example

Imagine inside a component you .subscribe() to some Observable that emits 10 values with a delay of 10 seconds between each value. If that component is destroyed after 5 seconds, the Observable chain will still emit values for another 95 and at that point the  interval used internally by RxJS to produce the 10 second delay will be cleaned up.

You could call subscription.unsubscribe() in the ngOnDestroy() method to clean up early and reclaim some memory 95 seconds early but since this Observable will emit a finite number of values you do not have to worry about a permanent allocation of resources due to your missing .unsubscribe().

Cleanup / post.unsubscribe()

I hope this was a clear explanation of a topic I found quite a few people asking while searching for an answer myself.

I detailed this topic originally in a stackoverflow answer where I provide some citations from sources much more reputable than myself verifying this answer.


Leave a Reply