What Is an Observable?
Observable is an abstraction of an asynchronous stream of data. For example, when we look at an
Observable, it represents a stream of strings that will be delivered one by one over time. TK (https://medium.com/isop-nepal/subscribe-vs-async-pipe-in-angular-21bb38f3ee49)
But when the
Observable gets modified, how do we display data? This is where we use
We pass the Observable around, combining it and saving it to different variables with different combinations of operators, but at the end, an
Observable<T> is useless on its own. We need a way to “terminate” the
Observable and extract the type
T out of it. That is what
.subscribe is used for: to subscribe to the resulting stream and terminate the observable. TK (https://kimsereyblog.blogspot.com/2018/05/async-pipe-versus-subscribe-in-angular.html)
We all recognize this pattern where I dispose of a subscription with the
With this pattern, I can be sure that my subscription will always be ended and I am safe from a memory leak! Note that we absolutely have to create the subscription during the initialization (
ngOnInit) of a component, and later when it’s being destroyed, we need to check if the subscription is still live, cancel it, and clear all references to it. TK (https://medium.com/angular-in-depth/why-you-have-to-unsubscribe-from-observable-92502d5639d0)
But for most regular situations where I am just doing a simple subscription to get the value of a variable and passing it to the template, this pattern becomes tedious very fast with an increasing number of subscriptions.
For example, see the code below:
So here is how I can avoid the subscription completely.
But first, let’s look at the code where it’s a simple consumption of an
Observable returned by a service function and how to handle this with the
Let’s assume I have a
serviceFunctionReturningObservable() function that returns me an observable of the following signature. And in the parent
component.ts file, I want to subscribe to that
Observable and pass that subscribed data down to
Children to be consumed.
serviceFunctionReturningObservable( flag: Flag ):
The suboptimal version of my code (without using an async pipe) with regular .subscribe()
And then in the corresponding .html template file, I access the data as follows:
Now to understand what’s happening above, we need to note that normally to render the result of a
Promise or an
Observable, we have to:
- Wait for a callback.
- Store the result of the callback in a variable.
- Bind to that variable in the template. TK (https://codecraft.tv/courses/angular/pipes/async-pipe/)
So going by that flow, what we are doing above is:
- Creating a boolean
Observablethat publishes out a boolean value within the
- Rendering the value of
isSomeBooleanVarToPassDownToChildCompin our template.
- Subscribing to the output of this
Observablechain and storing the boolean on the property
AsyncPipe, we can use
Observables directly in our template without having to store the result on an intermediate property or variable. TK (https://codecraft.tv/courses/angular/pipes/async-pipe/)
AsyncPipe accepts as argument an Observable or a Promise, calls
subscribe or attaches a then-handler, then waits for the asynchronous result before passing it through to the caller. TK (https://codecraft.tv/courses/angular/pipes/async-pipe/)
So for this case, we can do even better and never actually use
subscribe by using
“Unwraps a value from an asynchronous primitive.
The async pipe subscribes to an Observable or Promise and returns the latest value it has emitted. When a new value is emitted, the async pipe marks the component to be checked for changes. When the component gets destroyed, the async pipe unsubscribes automatically to avoid potential memory leaks.” — Angular’s documentation
Why Use AsyncPipe?
- Because it automatically subscribes and unsubscribes from
Observablesas the component gets instantiated or destroyed, which is a great feature.
- This is especially important in the case of long-lived
Observablesreturned by the router or by
- Also, because it makes our programs easier to read and more declarative with fewer state variables in our component classes.
AsyncPipe, we don’t need to perform the
subscribe and store any intermediate data on our component like so:
In case I had to pipe something with the initial subscribed data, I would have to do this:
We pipe our
Observable directly to the
AsyncPipe, it performs a subscription for us, and then it returns whatever gets passed to it. TK (https://codecraft.tv/courses/angular/pipes/async-pipe/)
By using AsyncPipe, we:
- Don’t need to call
Observableand store the intermediate data on our component.
- Don’t need to remember to unsubscribe from the
Observablewhen the component is destroyed.
- Have fewer state variables. TK (https://codecraft.tv/courses/angular/pipes/async-pipe/)
Another Example of the Principle
In the case below,
arrayListFromSelector$ is coming from a selector (using the
reselect package and consuming a
Initially, I was subscribing to that selector coming from
.subscribe() as follows.
Initial working code with .subscribe()
And then passing that subscribed data
arrayListFromSelector down to the
Child component where I will, in turn, just pass that data, as it is ultimately to be consumed by an
ng-select to be fed to a dropdown list.
Child component does not need to know anything about the
Final refactored code without using .subscribe()
arrayListFromSelector is available in the
Child, just as a local state variable.
Generally, the pattern of “subscribe and, in the subscription function, copy data into the state of the component” is not a healthy one. It gets you unnecessarily involved in change detection.
But there are some cases where you should explicitly subscribe to
Observables in components and directives.
For example, when the
Observable makes a change to the outside world. Most commonly, this is done by issuing a
PUT) through HTTP to a back-end API.
When working with
HttpClient, we might face a situation where we just can’t use
AsyncPipe for the
Observable. To dive deeper, let’s look at some examples:
- Re-sending requests when parameters are being changed.
- Receiving data in parallel from several streams.
- Sending individual requests.
- Creating, deleting, and updating data.
Also, when the component itself — and not Angular via a template — is consuming the data. It frequently happens when a component opens a modal dialog or sends a message to the user, like a pop-up or a “snackbar.”
In all those cases, the component is the entity that “wants” and “consumes” the
Observable to actually execute, so it also should be the one to subscribe.
But otherwise, whenever possible:
“We should always use
AsyncPipe when possible and only use
.subscribe when the side effect is an absolute necessity, as we are safe as long as we stay in the
Observable. The code terminating the
Observable should be the framework (Angular) and the last piece (the UI).” TK (https://kimsereyblog.blogspot.com/2018/05/async-pipe-versus-subscribe-in-angular.html)