RXJS is an asynchronous observable base event-based programming library and can be used to manage sequences of events. The main concepts are Observables, Observer, Observer, Operators, Subjects, Subscriptions and Schedulers. Using those core features, developers can build an application with RXJS to produce values using pure functions. This makes applications less prone to errors where other pieces of code in your application and mutate state.
The foundational bedrock of RXJS is the Observable and they are lazy push collections of multiple values. That's a simple explanation of how powerful a tool the Observable is. Observables are data producers and n RXJS, which is a push system, sends data to the consumers. This is like Promises but Promises deliver only a single value and the Promise itself is what determines when that value gets pushed.
Once an Observable has produced data, the observer consumes that data via a set of callbacks: next, error and complete. The observer is provided to the subscribe function of the observable as a parameter. The observer will then execute its next callback when the subscriber calls its next function.
The observable is firing the next function and passing our string value to an observer that is currently subscribed. Our test observer then logs the string that was passed in. Notice that the Next function on the observer fires every subscriber calls that next function but each time uses the new value that was passed in. The complete function stops the subscriptions and no further callbacks are made to the observers.
The subscription method also supports passing in functions directly. Internally, the subscription method will make a new observer and set the first function passed in as the next. The error and complete function can be set if passed in the same order.
The true power of the Observable comes into play when we have multiple observers subscribe to the same observable. If we combine our two test cases, we get this.
Which produces this:
One of the important things to note here is that when error occurs the subscription ends. In the preceding example removing the subsciprition.complete() call executes the error function and the observer does not execute any additional next calls.
The core of RXJS is observables and the operators are the tools you’ll use to max the most of them. Operators at their simplest are functions. There two categories of operators, Pipeable Operators and Creation operators.
Pipeable operators take an observable as a parameter and output a new observable. This allows the chaining of subscriptions because subscribing to the output observable also subscribes to the input variable. This is incredibly useful because it allows a function to manipulate the value of the first observable and output it another observable without altering the first. This limits potential collisions that would arise by altering the input observable.
In the original code snippet, add piping functions to get the value out of the first observable and add a bit of text to the message and finally return the altered value. Subscribing to the new observable produced by the pipe gives use an output that looks like this:
A more advanced type of Observable are subjects. They are both an observable and observer in one in one type. Subjects can consume multiple observers; this allows it to multicast to multiple observers at one time. Multiple observers can be subscribed, as you can see from our early examples, each one of those observers executes its code independently. Subjects handle the execution of all their observers concurrently.
In the preceding example, all the existing observers are assigned to the new test subject. Doing this produces a slightly different output.
All the observers respond to each next call concurrently. This opens possibilities for multi observers that are interconnected.
The last core concept in RXJS is Schedulers. They allow programmers to define the timing of when observables execute tasks. Schedulers are built with three different components, a data structure, an execution context and a timer. The scheduler can store, and queue tasks based on criteria. The execution context also gives programmatic control of when and where the tasks get executed. The timer is a virtual clock that is independent of the system clock that controls when the tasks get executed. RXJS has different types of schedulers it automatically uses when handling observables with the intent of using the least concurrency to execute the tasks.
The following code sets up an asynchronous timer that will change our name input. Typically, changing this input value in the ngAfterViewInit would cause an error. The error occurs because all subscriptions happen synchronously but by wrapping our change in a scheduler, we delay our setting of the input.
RXJS offers a wide and deep range of powerful ways to handle events. It fits ideally into situations where an event or asynchronous computation gets complicated and must build complex logic that interacts with state. It also shines when making multi asynchronous calls for data. There are other libraries that handle types of calls when they return only a single point of data. RXJS fits into the space these libraries can’t fill when operations handle multiple messages over their lifetime.
React and Angular are two of the leading reactive frameworks in the wild today. RXJS seamlessly integrates with Angular due in large part to its recent write using RXJS as part of its core. Parts of RXJS have been baked into Angular and just using the most recent version of Angular you’ll need a firm grasp of how to work with observables. While React isn’t built using RXJS it also works well with RXJS there are plenty of hooks that connect RX observables to React components.
The initial investment in learning RXJS can be quite high but the results are worth it. RX has multiple integration across multiple platforms that increases its reusability across disciplines. The myriad of operators it has access to simplifies and condenses code in smart intuitive.