Do you need to unsubscribe from Angular 2 http calls to prevent memory leak?
fetchFilm(index) { var sub = this._http.get(`http://example.com`) .map(result => result.json()) .map(json => { dispatch(this.receiveFilm(json)); }) .subscribe(e=>sub.unsubscribe()); ...
No, You don't need to unsubscribe it. It observes until getting a response from api. And once the Http request completes it unsubscribes automatically.
As you probably know when you subscribe to an observable or event in JavaScript, you usually need to unsubscribe at a certain point to release memory in the system. Otherwise, you will have a memory leak. A memory leak occurs when a section of memory that is no longer being…
complete() after it has emitted all of it's values. There's no need to unsubscribe. It completes on it's own, which means it unsubscribes all subscribers automatically. This is also the reason why you don't often notice any memory leaks.
So the answer is no, you don't. Ng2
will clean it up itself.
The Http service source, from Angular's Http XHR backend source:
Notice how it runs the complete()
after getting the result. This means it actually unsubscribes on completion. So you don't need to do it yourself.
Here is a test to validate:
fetchFilms() { return (dispatch) => { dispatch(this.requestFilms()); let observer = this._http.get(`${BASE_URL}`) .map(result => result.json()) .map(json => { dispatch(this.receiveFilms(json.results)); dispatch(this.receiveNumberOfFilms(json.count)); console.log("2 isUnsubscribed",observer.isUnsubscribed); window.setTimeout(() => { console.log("3 isUnsubscribed",observer.isUnsubscribed); },10); }) .subscribe(); console.log("1 isUnsubscribed",observer.isUnsubscribed); }; }
As expected, you can see that it is always unsubscribed automatically after getting the result and finishing with the observable operators. This happens on a timeout (#3) so we can check the status of the observable when it's all done and completed.
And the result
So, no leak would exist as Ng2
auto unsubscribes!
Nice to mention: This Observable
is categorized as finite
, on contrary to the infinite
Observable
which is an infinite stream of data can be emitted like DOM click
listener for example.
THANKS, @rubyboy for help on this.
OK so there's two reasons to unsubscribe from any observable. Nobody seems to be talking much about the very important second reason!
- Clean up resources. As others have said this is a negligible problem for HTTP observables. It'll just clean itself up.
- Prevent the
subscribe
handler from being run.
Note that with an HTTP observable, when you unsubscribe it will cancel the underlying request in your browser for you (you'll see 'Cancelled' in red in Network panel). This means time won't be wasted downloading or parsing the response. But that's actually an aside to my main point below.
The relevance of number 2 is going to depend upon what your subscribe handler does:
If your
subscribe()
handler function has any kind of side effect that is undesired if whatever calls it is closed or disposed then you must unsubscribe (or add conditional logic) to prevent it from being executed.
Consider a few cases:
A login form. You enter username and password and click 'Login'. What if the server is slow and you decide to hit Escape to close the dialog? You'll probably assume you weren't logged in, but if the http request returned after you hit escape then then you will still execute whatever logic you have there. This may result in a redirect to an account page, an unwanted login cookie or token variable being set. This is probably not what your user expected.
A 'send email' form.
If the subscribe
handler for 'sendEmail' does something like trigger a 'Your email is sent' animation, transfer you to a different page or tries to access anything that has been disposed you may get exceptions or unwanted behavior.
Also be careful not to assume unsubscribe()
means 'cancel'. Once the HTTP message is in-flight unsubscribe()
will NOT cancel the HTTP request if it's already reached your server. It will only cancel the response coming back to you. And the email will probably get sent.
If you create the subscription to send the email directly inside a UI component then you probably would want to unsubscribe on dispose, but if the email is being sent by a non-UI centralized service then you probably wouldn't need to.
onDestroy()
. Whether the consequences are trivial or not will depend upon what you do in the subscribe handler. If you try to update something that doesn't exist anymore you may get an error.Sometimes you may have some actions you would want if the component is disposed, and some you wouldn't. For example maybe you have a 'swoosh' sound for a sent email. You'd probably want this to play even if the component was closed, but if you try to run an animation on the component it would fail. In that case some extra conditional logic inside subscribe would be the solution - and you would NOT want to unsubscribe the http observable.
So in answer to the actual question, no you don't need to do it to avoid memory leaks. But you need to do it (often) to avoid unwanted side effects being triggered by running code that may throw exceptions or corrupt your application state.
Tip: The Subscription
contains a closed
boolean property that may be useful in advanced cases. For HTTP this will be set when it completes. In Angular it might be useful in some situations to set a _isDestroyed
property in ngDestroy
which can be checked by your subscribe
handler.
Tip 2: If handling multiple subscriptions you can create an ad-hoc new Subscription()
object and add(...)
any other subscriptions to it - so when you unsubscribe from the main one it will unsubscribe all the added subscriptions too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With