RxJS / Observables
This guide is intended to demystify observables and make them easier to understand. Every topic is accompanied by code examples along with JSBin links so you can try them yourself. The guide is written in an increasing order of complexity, but feel free to jump around using the navigation on the left.
Feedback is welcomed!
What is RxJS
Definition
RxJS is named after the term Reactive Programming. Reactive Programming is a paradigm that uses Observables as the basic building block of applications. Observables are streams of asynchronous data or events, streams of things.
An Observable is something that can be subscribed to, or observed. When a new value is emitted on the stream (Observable), anything that has subscribed to that observable is notified.
Asynchronous Arrays
At their heart, Observables are asynchronous arrays of values, and it’s helpful to think of them in this way: an array that populates over time.
The elements of that asynchronous array can come from anywhere: click events, API calls, file system operations, timers, manually from elsewhere in the app, etc.
The difference is if you define an array, you know the contents ahead of time. With an Observable, there is no guarantee that anything will be added, and no guarantee that nothing more will be added. You react when something is added. Hence the term reactive programming
.
JS Functional Array Operators
Observables and arrays are so closely related, that a lot of the operators for observables are analogous to native javascript array operators.
Let’s just focus on native javascript arrays. On the array prototype, several functional methods exist to transform the items within the array.
For example, let’s say you have the following array:
const sample = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
Now let’s say you want to double all the values. You could do something like this:
const doubled = sample.map(x => x * 2);
This will apply the function passed to map to every item in the array, returning a new array of the results. If you were to run this, you would get the following:
[ 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 ]
Now lets say you wanted to first grab all the evens, and then double them:
const doubledEvens = sample.filter(x => x % 2 == 0).map(x => x * 2);
If you were to run this, you would get the following:
[ 4, 8, 12, 16, 20 ]
Native JS Arrays have lots of these stream-like, functional operators available, including map
, filter
, reduce
, sort
, reverse
, join
, etc.
Array vs Observable Operators
Observables share a lot of these functional operators and work in very similar ways. Let’s compare a couple of array operators against their observable counterparts.
We saw that applying map
to an array, maps the supplied function across all items in the array and returns a new array.
An observable’s map
operator will map the supplied function to each item emitted from the stream and returns a new observable that emits the result.
For example, if the previous example looked like this:
// Array
const sample = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
// Array of doubled values
const doubled = sample.map(x => x * 2);
The observable version looks like this:
// Observable of Numbers
const sample = Observable.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Observable of Doubled Values
const doubled = sample.map(x => x * 2);
They are almost identical. The difference is that doubled in the array example is already defined, it was synchronous. You can console log that out and see all the values of the doubled array.
With the observable example, one would need to subscribe to the doubled observable, and the function you pass to subscribe will be called as values are emitted. That is to say that each step in the sequence is called as new values are emitted. If the sample observable were to emit a new value, say 20
, five minutes from now, it would be ran through the map function, and then handed off to your subscription.
The difference is synchronous vs asynchronous. It would be like if we push
ed the new value 20
to our array example, and then ran the mapping code again.
With observables the operators are describing a sequence of transformations to apply to every item emitted from the stream.