Observables provide a way for you to pass data around your application in a way that is arguably more flexible and declarative than the alternatives. Angular uses the RxJS implementation of Observables to handle many common async operations, including events, routing and handling HTTP requests and responses. In this blog I’ll provide an introduction to Observables in the context of an Angular application.
Observables have at least two participants. You have publishers or producers — functions that publish values, and subscribers that consume this data.
When the Promise resolves — a process which might take milliseconds or minutes — the response can be parsed to JSON and console logged. However, while each resolved Promise can only return a single value, an Observable can provide multiple values over time, pushing data to its consumers.
In contrast, a typical function is a pull system, where the function is a producer of data, and the consumer decides where and when the function is called, and pulls one return value from each function call.
For example, the below function will exit after the first return statement.
With Observables, you can call
subscriber.next() to return multiple values, as below:
The code contained within the scope of the Observable declaration represents the Observable execution. There are three types of values an Observable execution can deliver:
- “Next”: a value such as a Number, a String, an Object, etc.
- “Complete”: does not send a value.
After an ‘Error’ or ‘Complete’ notification is received, nothing can be delivered afterwards, much like a return statement in a regular function.
Another important thing to note about subscriptions is that by default, each subscription is independent of the other.
Observables help us to normalize the API you use for handling the ‘stream’ of asynchronous browser events that happen when your users interact with the front end of your application — click events, waiting for HTTP responses, interval timers, user form input, and so on.
Handling Observables in Angular
In Angular, rather than directly using
subscribe() in your components, you will usually use async pipes. This has a number of advantages.
Instead of waiting for a Promise to resolve, storing the returned value in a variable and using the variable in a template, we can reference our observable directly in the template.
Keeping your subscriptions open while not using them is a memory leak. By using async pipes, you can enroll the async data when the component is loaded, and unload it when it is torn down. Behind the scenes, the framework manages lifecycle so you don’t have to do it yourself. It’s easy to forgot to unsubscribe in ngOnDestroy(), and if you do forget, there won’t be an error, just a silent memory leak.
Angular uses the RxJS implementation of Observables both under the hood and in its own API. Observables help us to deal with the ‘stream’ of data and user input flowing around a modern frontend application. Async pipes handle the subscription process for us.