Angular manages unsubscribing from certain observable subscriptions like the HTTP service or the async pipe. However, it doesn’t clean up them all. The rest are up to you. RxJS is powerful and provides you several ways to handle your observables.
Manual Unsubscribe
The straightforward way to handle a subscription is to manually unsubscribe from it. The blueprint is an easy one: save the Subscription
then, when the time comes call unsubscribe()
. For our example, I’ll make a service request and set up a timer. The service is representative of any service that returns an Observable that won’t be handled by Angular, such as custom observable based code or working with a custom library. We’ll unsubscribe inside of ngOnDestroy, a lifecycle hook provided by Angular. As it names implies, it is called just before Angular destroys the component or directive. It’s purpose is to “cleanup just before Angular destroys the directive/component” including to “unsubscribe Observables and detach event handlers to avoid memory leaks.”
As you can see, with one or two items, it’s not too much work. You should also be able to see how it can get stacked up quickly, managing a variable and an unsubscribe (with an option safe check to make sure it exists) for each Observable. The safe check can really come into play with timers that may not always be running. If you look at this and think “there must be an easier way”, then you’re right.
takeUntil Operator
The second method to manage your subscriptions and their clean up is to use the takeUntil
operator. To do this, we need to compose our Observables differently, adding the takeUntil
operator and passing it a Subject
that you’ll update during the ngOnDestroy
. I’ll modify the previous code, but this time with takeUntil.
What we can see here is much simpler code. For each Observable we use, we compose it with the takeUntil operator and pass each the same Subject, in our code named ngUnsubscribe. We don’t need any other reference to the subscription, though for the case of the timer, I’m saving it in case we want to be able to stop it at any time. The purpose of the takeUntil operator is to “emit the values emitted by the source Observable until a notifier Observable emits a value.” The Subject (which extends Observable) we provide is the “notifier” so that when it says it is complete, the condition is met and all Observables using our ngUnsubscribe will complete. That is what we are seeing in ngOnDestroy. When the component is destroyed we call next and complete on the subject, which will in turn tell the observables that they are complete. Now, we can add as many new Observables as we want without needing to add more Subscription variables and more manual unsubscribes.
tl;dr
Don’t store subscriptions and manually unsubscribe. Instead, give every observable the same subject through takeUntil
and complete the subject in ngOnDestroy to manage all observables at once.