RxJS

A quick tutorial on the Javascript Reactive Programming library


Introduction

RxJS is a library for reactive programming, which put simply, is when you build your program in a way that all it's doing is reacting to data changes. It's a subset of event-driven programming and actually, you don't have to use RxJS for pure reactive programming; it can be used as way of making event driven programmming much simpler.

I believe RxJS is very simple to grasp, but it's difficulty comes from bad documentation that doesn't explain the basic concepts well, mixed in with the massive number of helper functions (which are great though) that obfuscate to newcomers where to start in order to understand the underlying structures that make everything work. Hopefully this tutorial will give you a foundation to RxJS so that anytime you see a new reactive function, you'll clearly understand what's going on.

What This Tutorial Covers

What This Tutorial Covers
  1. Observables
  2. Subscriptions
  3. Helper Functions ("Operators")
  4. Chaining & Reuse

What You Need For This Tutorial

What You Need For This Tutorial

Nothing unless you want to experiment, in which case: a Javascript playground with RxJS


Importing

I believe some frameworks, like Angular, come with the library installed. For everyone else, you can do this:


npm install rxjs
      

Or, if you want to load the library on the front-end from a CDN:


<script src="https://unpkg.com/rxjs/bundles/rxjs.umd.min.js"></script>
      

Below is an example of getting the Rx object using es6 modules import and commonJS require:


// es6 modules
import { Rx } from 'rxjs/Rx';

// commmonjs
const Rx = require('rxjs');

// example usage:
Rx.from([1,2,3]);
      

You also have the option to import only the stuff you need:


import { Observable, from, of, range } from 'rxjs';
// or
const { Observable, from, of, range } = require('rxjs');

// now you don't need to prepend 'Rx.'
from([1,2,3]);
      

Observables

An Observable is an object that emits one or more values. We'll be able to listen for these values later on. Here is how you create an observable:


Rx.Observable.create(observer => {
    // you can call the next function multiple times to emit multiple values
    observer.next('some-value-to-emit');
});
      

So how is this useful? You could place an event listener in there that calls observer.next() with a value whenever an event occurs. You could also place an XMLHttpRequest with transfer chunk encoding that calls observer.next() whenever it receives data. Or whatever, but the point is that this object can emit values a variable number of times, unlike the Promise which really requires you to know how many times you're expecting data to be emitted.

Subscriptions

A Subscription executes an observable and receives its emitted values in their final states.


observable.subscribe(value => { console.log(value); });
      

The function passed to subscribe will be called everytime the observable emits data. In a nutshell, that's all there is to RxJS. The complexity comes from all the helper functions and functionality the library provides. Just to be clear: the only two functions you need are create & subscribe. Everything that comes after that are just convenient functions and tools to make programming easier.

Helper Functions

These are usually called "Operators", but I think Helper Functions are better because that clearly explains what they're doing, which is adding commonly used functionality into easy to use functions. I put them into five categories:

Creation Functions used to create observables from things like events, data structures, promises, etc.
Combination Functions used to combine observables or the values emitted by observables.
Filtering Functions used to filter out values that are emitted.
Transformation Functions used to alter the values being emitted.
Special Random utility functions that don't alter emitted values, like do/tap, toPromise, retry, delay, and catch.

So far, the best place I've found to learn all of these helper functions is LearnRxJS.

Chaining, Let, & Pipe

All of these functions (except for the subscribe function), returns an observable. This allows for chaining and some other neato coding techniques.

Chaining

You can chain all of these functions to together:


from([0,1,2,3]).delay(1000).map(x => x * 2).subscribe(x => { console.log(x) });
      

Let

You can save the observable returned by any helper function and reuse them using the let function:


const emit1 = delay(1000);
const map2 = map(x => x * 2);
from([0,1,2,3]).let(emit1).let(map2).subscribe(x => { console.log(x) });
      

Pipe

Instead of using let for every observable you want to reuse, you can just pass all of the arguments to the pipe function:


const emit1 = delay(1000);
const map2 = map(x => x * 2);
from([0,1,2,3]).pipe(emit1,map2).subscribe(x => { console.log(x) });
      

Done!

You should have strong foundational understanding of RxJS now. In time, as you learn all the helper functions it offers, I think you'll like programming with RxJS way more than you did with callbacks and promises.