Traditionally this has been handled with callback functions and events. However if you have ever dealt with complex JS applications, you know this can quickly get very messy and hard to reason about, because the code doesn't follow normal control-flow. Furthermore, there are certain patterns you find yourself re-implementing over and over again.
This is where RxJS comes in. It introduces a powerful paradigm for working with these kinds of asynchronous computations and makes them first-class citizens in your code. We've found the reactive pattern incredibly useful across the whole Radix stack.
At the core of RxJS are observables and observers. An observable represents a collection of any number of future values. You can think of it as a function that can return a stream of results indefinitely into the future. An observer is simply a set of 3 callback functions that handle the returned values.
This is best explained with a quick example. First, let's create an observable. This observable will return 1, 2 and 3 as soon as you subscribe to it, and 4 a second later asynchronously.
Now we need to create an Observer which will invoke the Observable, receive the values and output them to console. Like I mentioned before, an observer is just an object consisting of 3 callback functions - they are next, complete and error. Next is invoked when a new value is returned, complete means the observable won't return any more values and error means something has gone wrong.
If you were to run this code you would see the following output in the debug console
Observables are unicast, meaning every time you call subscribe on an observable you get a new and independent execution of that observable. But sometimes you want to allow multiple observers to listen to the same values, for example if you're broadcasting status updates for some system.
This is where Subjects come into play. From an Observer's point of view, they are indistinguishable from a regular Observable - you call subscribe on them in exactly the same way.
Interestingly, they also look just like Observer's from the outside - to push the next value, you call subject.next(value). Later you call subject.complete() finish the execution.
An example will demonstrate this better than I can ever explain:
Running this code will produce the following output
RxJS also provides a few useful variations of subjects, such as BehaviorSubject which stores the last value and immediately returns it to every new observer, useful if you're broadcasting the current state of a system, and a ReplaySubject which can store and replay multiple previous values.
On top of these basic abstractions, RxJS provides a large toolset for manipulating these streams called Operators. They allow you to work with streams of a data in a composable functional style. Operators do not modify the existing observable, instead they return a new and modified observable, which means you don't have to worry about accidentally messing up your observables.
Here is an example of how you might chain operators to modify an observable.
This example takes a stream of numbers, filters out any values less than 3 and then doubles each value.
There are many different operators available, and they broadly fall into creation, filtering, transformation and combination operators.
Creation operators allow you to create observables from different inputs, such as arrays of values or events and promises.
Filtering operators let you filter streams based on the values of the incoming items, but also based on things like time elapsed between events, for example the debounce operator.
Transformation operators include things like map which applies a transformation to every item going through, as well as ones that combine multiple values like groupBy and reduce
Combination operators let you take multiple observable streams and merge them into one, such as merge, concat and zip, but also more advanced ones like buffer, which collects the values of one observable and releases them when a trigger observable emits an event.
This site provides a great overview of all available RxJS operators:- https://www.learnrxjs.io/
I've only scratched the surface of reactive streams. It's a powerful paradigm that changes the way you think about asynchronous programming. If you want to read further, I can recommend this excellent in-depth tutorial by André Staltz:- [https://gist.github.com/staltz/868e7e9bc2a7b8c1f754]. You can also take a look at RxJS documentation here:- [http://reactivex.io/rxjs/manual/overview.html#introduction]
Next time I'll return with an introduction to Entity-Component-Systems - a design pattern from game programming for which we have found a surprising use in the Radix architecture.