Exploring the pillars of reactive programming
Let's begin with a little bit of background!
Reactive programming is among the major programming paradigms used by developers worldwide. Every programming paradigm solves some problems and has its own advantages. By definition, reactive programming is programming with asynchronous data streams and is based on observer patterns. So, let's talk about these pillars of reactive programming!
Data streams
Data streams are the spine of reactive programming. Everything that might change or happen over time (you don't know when exactly) is represented as a stream, such as data, events, notifications, and messages. Reactive programming is about reacting to changes as soon as they are emitted!
An excellent example of data streams is UI events. Let's suppose that we have an HTML button, and we want to execute an action whenever a user clicks on it. Here, we can think of the click event as a stream:
//HTML code <button id='save'>Save</button> //TS code const saveElement = document.getElementById('save'); saveElement.addEventListener('click', processClick); function processClick(event) { console.log('Hi'); }
As implemented in the preceding code snippet, in order to react to this click event, we register an EventListener
event. Then, every time a click occurs, the processClick
method is called to execute a side effect. In our case, we are just logging Hi
in the console.
As you might have gathered, to be able to react when something happens and execute a side effect, you should listen to the streams to become notified. We can say listen or observe to get closer to the reactive terminology. And this leads us to the observer design pattern, which is at the heart of reactive programming.
Observer patterns
The observer pattern is based on two main roles: a publisher and a subscriber.
A publisher maintains a list of subscribers and notifies them or propagates a change every time there is an update. On the other hand, a subscriber performs an update or executes a side effect every time they receive a notification from the publisher:
So, to get notified about any updates, you need to subscribe to the publisher. A real-world analogy would be a newsletter; you don't get any emails if you don't subscribe to a newsletter.
This leads us to the building blocks of RxJS. They include the following:
- Observables: These are a representation of the data streams that notify the observers of any change.
- Observers: These are the consumers of the data streams emitted by observables.
RxJS combines the observer pattern with the iterator pattern and functional programming to process and handle asynchronous events.
This was a reminder of the fundamentals of reactive programming. Remember, it is crucial to understand when to put a reactive implementation in place and when to avoid it.
In general, whenever you have to handle asynchronous tasks in your Angular application, always think of RxJS. The main advantages of RxJS over other asynchronous APIs are listed as follows:
- RxJS makes dealing with event-based programs, asynchronous data calls, and callbacks an easy task.
- Observables guarantee consistency. They emit multiple values over time so that you can consume continuous data streams.
- Observables are lazy; they are not executed until you subscribe to them. This helps with writing declarative code that is clean, efficient, and easy to understand and maintain.
- Observables can be canceled, completed, and retrieved at any moment. This makes a lot of sense in many real-world scenarios.
- RxJS provides many operators with a functional style to manipulate collections and optimize side effects.
- Observables push errors to the subscribers and provide a clean way to handle errors.
- RxJS allows you to write clean and efficient code to handle asynchronous data in your application.
Now that we have given some insight into the reactive programming pillars and detailed the major advantages of RxJS, let's shed some light on the relationship between Angular and RxJS.