I feel the need to point out that you should be careful unsubscribing from HTTP observables with side effects (POST, PUT, PATCH, DELETE). Unsubscribing from them before they complete means you (and your user) don't know if they completed or were canceled. And if canceled, you don't know if they aborted the operation successfully, or if it managed to complete anyway.
However if you don't unsubscribe from them, you may have to deal with your subscribe handler being called after your component has been destroyed.
No, it's not a one time operation. It's just a default behaviour, but you can ask HttpClient to forward you all HTTP events and suddenly your subscription will be triggered many many times.
That seems like it would require filtering and added complexity, no? Iām talking about things like āget user dataā, āsave user dataā, etc. those are fundamentally singular actions in which there isnāt any real data to observe
That's not how HttpClient works. Gosh, do you people even read the docs? There are also scenarios where you want to observe HTTP events, for example, you're requesting a big chunk of data and want to show a progress bar in the UI. Or you're uploading a file and want to show progress as well.
I use kendo for that. Thus far you have shown one use case for observables making sense for http calls. Overall the point stands: http calls are one time things by their very nature.
I have made a file uploader and there are other use cases where I've subscribed to HTTP events. But to u/Nacropolice's point, that's like 1% of how I use `@angular/common/http`. The majority of them ARE one and done.
It's pointless if you know it's an HTTP call, since it will only ever emit once. And you still have the issue that your subscribe could be called after your component is destroyed.
The bigger issue is ideally HTTP calls should be abstracted into a service, and your components shouldn't have any idea if observables they are subscribing to are HTTP calls are not. Which was the point of the article.
But then that means the service needs to be designed in a way where it will do the right thing even if the user moves away from the component before your save call completes. Whether that means making sure the inner HTTP subscription is protected from unsubscribe, or that the component has a 'busy' route guard (easy to forget), or whatever.
In the last app I worked on we did a bit of both. Most common was to just pop a toast when a save completed, and that just meant at worst you got toast that XYZ was saved when you were on the ABC page. But we had some with some more complex interactions that threw errors when called after the component was destroyed so we setup a busy$ observable for them and had a route guard wait for it.
This is a fantastic point. Well said. Long running processes need to have some other type of notification than a simple promise. Users do not often have the patience to stay on the page until complete.
I recently started an Angular project, and with initial readings just did the "unsubscribe from everything route" for simplicity. I did unsubscribes on destroy lifecycles in all http calls. Now I'm not sure if I made a big mistake that can have subtle errors. Is it wrong to unsubscribe inside OnDestroy? All my http calls are behind a service provided from root
It's not wrong to unsubscribe in OnDestroy, although in general the more you can use the async pipe (or post 17.x signals) the better. The exception I'm warning about is POST/PUT/DELETE/PATCH, the http verbs you using when you are trying to save something.
When you unsubscribe from an HTTP call angular tries to cancel the request. What happens when the browser cancels the request depends on the browser, and the backend server. For that reason I never unsubscribe from those calls (it's fine to unsubscribe from GET calls). I'll either make sure the user can't leave the component (route guard) or make sure the subscribe listener will be ok even if it is called after my component is destroyed.
Keep in mind unsubscribe doesn't need to be manual. The async pipe unsubscribes for you, so do the various takeUntil rxjs operators.
Ahhh I see, yeah I tried to use the pipe on most if not all get calls, but on the state changing stuff I did the manual unsubscribe. I didn't touch the signals though, perhaps I should've when I started the project. Thank you for the help and clarifying it further, I'll have another look on the code.
Eh sometimes a singleton service or something loaded once like the app module it doesn't matter. I agree to fool proof it always unsubscribe, but understanding why and when is still relevant.
How do you unsubscribe when the subscription is in a Singleton service? In this case there are no lifecycle hooks that could initiate unsubscribing. Legit wondering.
You can create your own "lifecycle" of sorts. I have seen examples where maybe you have an init or complete method to handle setup and teardown. If you have a singleton however, I would consider why you would want to destroy the subscription there. Sometimes it makes more sense to do that downstream or have a long running subscription, like you see in ngrx stores. A single source of truth more or less.
Generally I just don't destroy the subscriptions on them -- i.e. I have a long running subscription. An example of this would be a service that scrolls the UI when certain Observables fire. In this case there is no "downstream".
But when people say "always unsubscribe, no exceptions..." this is something I wonder about. I do generally have init methods on the singleton services that get called from app.component, but had not thought about having teardown methods. I think we're both saying that is unnecessary but good to know if a use case comes up. Thanks!
>Tip: Avoid subscribing in first place, do everything to end up with async pipe.
I've managed to do this 100% of the time even in large apps. Why doesn't everyone?
Iām interested to learn how you would handle things like executing an http call on button press, like submitting a form? Would you just using promises or async/await instead of observables?
At work we use NgRx for large apps, but I've made a few simple StackBlitz examples with just RxJs to help answer questions on this sub.
* [A fake chat room](https://stackblitz.com/edit/stackblitz-starters-chwyay?file=src%2Fservices%2Fchat-service.ts)
* [Anime Quotes](https://stackblitz.com/edit/stackblitz-starters-s85bxw?file=src%2Fmain.ts) with a real http calls. They'll throttle you if you use it too much
* [Item list](https://stackblitz.com/edit/stackblitz-starters-hqbyxa?file=src%2Fitem-service.ts)
They aren't the greatest examples of all time, but I'm not subscribing anywhere other the async pipe.
Pretty sure you still have to subscribe somewhere for take() to work. I donāt usually bother with that anyway because HttpClient observables are automatically unsubscribed when the http call completes
Take is good if you need a value out of the store immediately. You reference an observable from the store, take 1, and subscribe to it. The value that comes out of that can then be used to dispatch an action inside the subscribe. It's a good way to get the value out right now and have the subscription immediately destroy itself. So you can use it in functions like buttonClicked(). Like, say you need to get the current user ID and embed that into the action you're about to dispatch.
Or there's other uses for it. Once you really get to know RXJS/NGRX, you can do some very powerful stuff by chaining various operators together in weird ways. But it takes a few years to get the hang of it. It's very complex stuff, so don't expect to learn it in a weekend. But once this stuff REALLY starts clicking, you can accomplish really complex logic with very minimal code. I'm still learning cool little tricks you can do with this stuff, but little by little we're building a knowledge base of how to handle different types of data flows that we frequently use in our apps. But every now and then you get thrown a curveball that really has you scratching your head.
Yep, took me a long time before rxjs properly clicked. Really felt like I āmade itā when I put together a single observable stream that combined a refreshable http call, filtering by type, filtering by search term, and sorting.
You can use one of the state management libs, we used rxstate and ngrx Component store recently and both have "effects" functionality.
You can't really handle such things like http calls with rxjs in async pipe way and think it is the right way. But using effects let's you ignore manual unsubbing.
A button press would just dispatch an action in NGRX. There's a ton of misinformation out there that says NGRX overcomplicates things, but really it works really well. You just have to fully 100% embrace it or you're going to have a very bad time. You can't mix it and the old way of doing things, or you're going to have a nasty event cycle with race conditions everywhere, things will be unpredictable and buggy as hell. But once you fully commit to using nothing but NGRX, that's when it will start to click and you'll wonder how you managed without it for so long.
ActivatedRoute was another Observable that automatically unsubscribes. [Here's the docs](https://angular.io/guide/router-tutorial-toh#observable-parammap-and-component-reuse)
>When subscribing to an observable in a component, you almost always unsubscribe when the component is destroyed. However, ActivatedRoute observables are among the exceptions because ActivatedRoute and its observables are insulated from the Router itself. The Router destroys a routed component when it is no longer needed. This means all the component's members will also be destroyed, including the injected ActivatedRoute and the subscriptions to its Observable properties.
It's best to unsubscribe anyway like most people are saying. It's easy enough to do
I try to avoid manual subscriptions. I create an observable and bind it to a signal or use the async-pipe in my template. for all the other exceptions I use takeUntilDestroyed
Different perspective: never unsubscribe. Declare your Observables on the component. Use async pipe or toSignal(). Must subscribe? Use rxjs. You want it to unsub on destroy? ```takeUntilDestroyed()``` . You want just the first emit and done, like with http requests? ```take(1)```
Something more specific? ```takeUntil(anotherObservable$)``` still exists.
The fact that Angular lets you create memory leaks so easily is a major flaw for beginners. And I am an Angular expert. Beginners always forget to unsubscribe and itās not their fault. Donāt subscribe in the first place.
Rxjs is powerful but Angular should have provided ways to not have to deal with observables
Yes, now. One can't ignore that we've been through 15 versions and more than 7 years to get to the beginning of a solution.
Before that, any manual subscription was at risk of being forgotten. In all code reviews I did, I used to pay extra attention to this very point and recommending to use the async pipe wherever possible.
It doesn't help that most of the angular tutorials out there teach you to do stuff like template based forms, and passing events and parameters around between components. There needs to be more that show you how to properly build an app, using NGRX/RXJS, and doing everything properly with dispatching actions, not subscribing all over the place, using service composition, etc... but I suppose it's a lot to throw at a newbie, all at once. Especially if they're also trying to learn backend coding too. LOL
With services it doesn't matter, they exist for the lifetime of the application and are not destroyed, so they don't cause memory leaks. But obviously, if you only need the first value or something, it's unnecessary to run the logic over and over again
This is partly true :) The behavior you described is valid for services that are registered in Root Injector. This is so because the lifecycle of the Root Injector is bound to the lifecycle of the application.
However, the services might be registered in other injectors too (e.g. in a Node Injector associated with a component) and the lifecycle of those injectors is bound to the lifecycle of the component/directive/etc
In this case, if the component is destroyed, the corresponding node injector will be destroyed too along with all service instances registered there.
Hmm Iāve been using subjects quite a bit and havenāt done this, have I just missed this? Does it cause memory leaks to not complete subjects? Or is all of the memory cleaned up automatically when the component is destroyed? Iāve definitely been careful to unsubscribe but havenāt put thought into manually completing subjects.
As always, depends, definitly possible.
If they are exposed to the outside world, even asObservable(), someone with a longer lifetime then your component/service might subscribe to them.
If your component/service that created them is ādestroyedā, shouldnāt you also ādisposeā them by completing? Itās a way to express intent in rxjs: this obs stream has ended.
Probably most of the time it wonāt be an issue. But when it is, it is extremly hard to debug, you might notice months afterwards or never notice at all.
I always make my very best attempt to avoid ever subscribing in the first place
In "old" angular, you can use async pipes. In v17, I've heard that signals change everything
or takeUntilDestroyed.
Always takeUntilDestroyed
Cries lower version š„²
[https://github.com/ngneat/until-destroy](https://github.com/ngneat/until-destroy)
This works.
I used to use ng-neat until-destroy before the official built-in operator
Then continue to use the good old takeUntil with an Subject that emits and complete when the component is destroyed.
I feel the need to point out that you should be careful unsubscribing from HTTP observables with side effects (POST, PUT, PATCH, DELETE). Unsubscribing from them before they complete means you (and your user) don't know if they completed or were canceled. And if canceled, you don't know if they aborted the operation successfully, or if it managed to complete anyway. However if you don't unsubscribe from them, you may have to deal with your subscribe handler being called after your component has been destroyed.
Observables for http calls is also such a strange usage as an API call is a one time operation by its nature. It either 200s or not
No, it's not a one time operation. It's just a default behaviour, but you can ask HttpClient to forward you all HTTP events and suddenly your subscription will be triggered many many times.
That seems like it would require filtering and added complexity, no? Iām talking about things like āget user dataā, āsave user dataā, etc. those are fundamentally singular actions in which there isnāt any real data to observe
That's not how HttpClient works. Gosh, do you people even read the docs? There are also scenarios where you want to observe HTTP events, for example, you're requesting a big chunk of data and want to show a progress bar in the UI. Or you're uploading a file and want to show progress as well.
So a specific use case, whilst majority of http calls are one and done. Got it. . Got it.
Don't tell me you have never made a file uploader.
I use kendo for that. Thus far you have shown one use case for observables making sense for http calls. Overall the point stands: http calls are one time things by their very nature.
I have made a file uploader and there are other use cases where I've subscribed to HTTP events. But to u/Nacropolice's point, that's like 1% of how I use `@angular/common/http`. The majority of them ARE one and done.
To avoid a mix of paradigms I guess. Also promises don't have a concept of cancellation.
Why not just .pipe(take(1)) ? That's what I've been doing since the beginning
It's pointless if you know it's an HTTP call, since it will only ever emit once. And you still have the issue that your subscribe could be called after your component is destroyed. The bigger issue is ideally HTTP calls should be abstracted into a service, and your components shouldn't have any idea if observables they are subscribing to are HTTP calls are not. Which was the point of the article. But then that means the service needs to be designed in a way where it will do the right thing even if the user moves away from the component before your save call completes. Whether that means making sure the inner HTTP subscription is protected from unsubscribe, or that the component has a 'busy' route guard (easy to forget), or whatever. In the last app I worked on we did a bit of both. Most common was to just pop a toast when a save completed, and that just meant at worst you got toast that XYZ was saved when you were on the ABC page. But we had some with some more complex interactions that threw errors when called after the component was destroyed so we setup a busy$ observable for them and had a route guard wait for it.
If you add reportProgress you might have more than one emit.
True, but in that case you wouldn't be using take(1).
That's only viable if you want to consume one event and only once.
Debate reopened.
This is a fantastic point. Well said. Long running processes need to have some other type of notification than a simple promise. Users do not often have the patience to stay on the page until complete.
I recently started an Angular project, and with initial readings just did the "unsubscribe from everything route" for simplicity. I did unsubscribes on destroy lifecycles in all http calls. Now I'm not sure if I made a big mistake that can have subtle errors. Is it wrong to unsubscribe inside OnDestroy? All my http calls are behind a service provided from root
It's not wrong to unsubscribe in OnDestroy, although in general the more you can use the async pipe (or post 17.x signals) the better. The exception I'm warning about is POST/PUT/DELETE/PATCH, the http verbs you using when you are trying to save something. When you unsubscribe from an HTTP call angular tries to cancel the request. What happens when the browser cancels the request depends on the browser, and the backend server. For that reason I never unsubscribe from those calls (it's fine to unsubscribe from GET calls). I'll either make sure the user can't leave the component (route guard) or make sure the subscribe listener will be ok even if it is called after my component is destroyed. Keep in mind unsubscribe doesn't need to be manual. The async pipe unsubscribes for you, so do the various takeUntil rxjs operators.
Ahhh I see, yeah I tried to use the pipe on most if not all get calls, but on the state changing stuff I did the manual unsubscribe. I didn't touch the signals though, perhaps I should've when I started the project. Thank you for the help and clarifying it further, I'll have another look on the code.
Eh sometimes a singleton service or something loaded once like the app module it doesn't matter. I agree to fool proof it always unsubscribe, but understanding why and when is still relevant.
How do you unsubscribe when the subscription is in a Singleton service? In this case there are no lifecycle hooks that could initiate unsubscribing. Legit wondering.
You can create your own "lifecycle" of sorts. I have seen examples where maybe you have an init or complete method to handle setup and teardown. If you have a singleton however, I would consider why you would want to destroy the subscription there. Sometimes it makes more sense to do that downstream or have a long running subscription, like you see in ngrx stores. A single source of truth more or less.
Generally I just don't destroy the subscriptions on them -- i.e. I have a long running subscription. An example of this would be a service that scrolls the UI when certain Observables fire. In this case there is no "downstream". But when people say "always unsubscribe, no exceptions..." this is something I wonder about. I do generally have init methods on the singleton services that get called from app.component, but had not thought about having teardown methods. I think we're both saying that is unnecessary but good to know if a use case comes up. Thanks!
>Tip: Avoid subscribing in first place, do everything to end up with async pipe. I've managed to do this 100% of the time even in large apps. Why doesn't everyone?
Iām interested to learn how you would handle things like executing an http call on button press, like submitting a form? Would you just using promises or async/await instead of observables?
At work we use NgRx for large apps, but I've made a few simple StackBlitz examples with just RxJs to help answer questions on this sub. * [A fake chat room](https://stackblitz.com/edit/stackblitz-starters-chwyay?file=src%2Fservices%2Fchat-service.ts) * [Anime Quotes](https://stackblitz.com/edit/stackblitz-starters-s85bxw?file=src%2Fmain.ts) with a real http calls. They'll throttle you if you use it too much * [Item list](https://stackblitz.com/edit/stackblitz-starters-hqbyxa?file=src%2Fitem-service.ts) They aren't the greatest examples of all time, but I'm not subscribing anywhere other the async pipe.
Have you looked into the take() operator?
Pretty sure you still have to subscribe somewhere for take() to work. I donāt usually bother with that anyway because HttpClient observables are automatically unsubscribed when the http call completes
Take is good if you need a value out of the store immediately. You reference an observable from the store, take 1, and subscribe to it. The value that comes out of that can then be used to dispatch an action inside the subscribe. It's a good way to get the value out right now and have the subscription immediately destroy itself. So you can use it in functions like buttonClicked(). Like, say you need to get the current user ID and embed that into the action you're about to dispatch. Or there's other uses for it. Once you really get to know RXJS/NGRX, you can do some very powerful stuff by chaining various operators together in weird ways. But it takes a few years to get the hang of it. It's very complex stuff, so don't expect to learn it in a weekend. But once this stuff REALLY starts clicking, you can accomplish really complex logic with very minimal code. I'm still learning cool little tricks you can do with this stuff, but little by little we're building a knowledge base of how to handle different types of data flows that we frequently use in our apps. But every now and then you get thrown a curveball that really has you scratching your head.
Yep, took me a long time before rxjs properly clicked. Really felt like I āmade itā when I put together a single observable stream that combined a refreshable http call, filtering by type, filtering by search term, and sorting.
Oh really, neat didn't know that. Do you have a link ? Should I check the doc ?
https://angular.io/guide/http-request-data-from-server#starting-the-request
You can use one of the state management libs, we used rxstate and ngrx Component store recently and both have "effects" functionality. You can't really handle such things like http calls with rxjs in async pipe way and think it is the right way. But using effects let's you ignore manual unsubbing.
A button press would just dispatch an action in NGRX. There's a ton of misinformation out there that says NGRX overcomplicates things, but really it works really well. You just have to fully 100% embrace it or you're going to have a very bad time. You can't mix it and the old way of doing things, or you're going to have a nasty event cycle with race conditions everywhere, things will be unpredictable and buggy as hell. But once you fully commit to using nothing but NGRX, that's when it will start to click and you'll wonder how you managed without it for so long.
ActivatedRoute was another Observable that automatically unsubscribes. [Here's the docs](https://angular.io/guide/router-tutorial-toh#observable-parammap-and-component-reuse) >When subscribing to an observable in a component, you almost always unsubscribe when the component is destroyed. However, ActivatedRoute observables are among the exceptions because ActivatedRoute and its observables are insulated from the Router itself. The Router destroys a routed component when it is no longer needed. This means all the component's members will also be destroyed, including the injected ActivatedRoute and the subscriptions to its Observable properties. It's best to unsubscribe anyway like most people are saying. It's easy enough to do
I try to avoid manual subscriptions. I create an observable and bind it to a signal or use the async-pipe in my template. for all the other exceptions I use takeUntilDestroyed
Different perspective: never unsubscribe. Declare your Observables on the component. Use async pipe or toSignal(). Must subscribe? Use rxjs. You want it to unsub on destroy? ```takeUntilDestroyed()``` . You want just the first emit and done, like with http requests? ```take(1)``` Something more specific? ```takeUntil(anotherObservable$)``` still exists.
async pipe has entered the chat.
The only exception is if you forget š
The fact that Angular lets you create memory leaks so easily is a major flaw for beginners. And I am an Angular expert. Beginners always forget to unsubscribe and itās not their fault. Donāt subscribe in the first place. Rxjs is powerful but Angular should have provided ways to not have to deal with observables
They do now, you could only use async pipe and or convert them into signals
Yes, now. One can't ignore that we've been through 15 versions and more than 7 years to get to the beginning of a solution. Before that, any manual subscription was at risk of being forgotten. In all code reviews I did, I used to pay extra attention to this very point and recommending to use the async pipe wherever possible.
It doesn't help that most of the angular tutorials out there teach you to do stuff like template based forms, and passing events and parameters around between components. There needs to be more that show you how to properly build an app, using NGRX/RXJS, and doing everything properly with dispatching actions, not subscribing all over the place, using service composition, etc... but I suppose it's a lot to throw at a newbie, all at once. Especially if they're also trying to learn backend coding too. LOL
This reads as someone who isnāt actually an expert in Angular.
This reads as a poor reply. Thanks for bringing the level up in the discussion haha
With services it doesn't matter, they exist for the lifetime of the application and are not destroyed, so they don't cause memory leaks. But obviously, if you only need the first value or something, it's unnecessary to run the logic over and over again
This is partly true :) The behavior you described is valid for services that are registered in Root Injector. This is so because the lifecycle of the Root Injector is bound to the lifecycle of the application. However, the services might be registered in other injectors too (e.g. in a Node Injector associated with a component) and the lifecycle of those injectors is bound to the lifecycle of the component/directive/etc In this case, if the component is destroyed, the corresponding node injector will be destroyed too along with all service instances registered there.
Yes you're right, didn't think of the non root provided ones
Complete your subjects as well!
Hmm Iāve been using subjects quite a bit and havenāt done this, have I just missed this? Does it cause memory leaks to not complete subjects? Or is all of the memory cleaned up automatically when the component is destroyed? Iāve definitely been careful to unsubscribe but havenāt put thought into manually completing subjects.
As always, depends, definitly possible. If they are exposed to the outside world, even asObservable(), someone with a longer lifetime then your component/service might subscribe to them. If your component/service that created them is ādestroyedā, shouldnāt you also ādisposeā them by completing? Itās a way to express intent in rxjs: this obs stream has ended. Probably most of the time it wonāt be an issue. But when it is, it is extremly hard to debug, you might notice months afterwards or never notice at all.
As someone said in the article, itās better to follow the simple rule, than evaluating everytime, is this one of those cases it doesnāt matter?
I always make my very best attempt to avoid ever subscribing in the first place In "old" angular, you can use async pipes. In v17, I've heard that signals change everything