RxJS in Plain English
A Gentle Introduction to RxJS

Preamble

The code samples in this guide are written in TypeScript, a strict superset of JavaScript which introduces type annotations. Even if you’re only familiar with JavaScript you should still be able to follow along.

Overview

RxJS has two fundamental concepts: observerables and operators.

An observable pushes a sequence of values to an observer.

An operator takes one or more operands and returns a new observable.

Observables vs Promises

A promise can push only one value whereas an observable can push one or more values.

Observables 101

Creating an Observable

The first step is to define our observer.

An observer is a data consumer. It is an object which complies with the Observer<T> interface, meaning at minimum it implements a next() method. Methods error(), and complete() are optional.

Next we create our observable.

An observable is a data producer. Our observable pushes a sequence of three random numbers to an observer.

Now, we subscribe our observer to our observable. As soon as we do this, the sequence of three random numbers is pushed one-by-one, from our observable to our observer. By default the observable will execute synchronously (i.e. the Observable<T>.subscribe() method will block until all values in the sequence are pushed).

Finally, now that our sequence has completed, we unsubscribe our observer from our observable.

The output of our program looks like this:

0.20054989954113478
0.19937995087489435
0.8817196944251975
end of sequence

Process finished with exit code 0

Creating an Observer Shorthand

If we have no need for error() and complete(), we can create an observer just by passing a next() function to the Observable<T>.subscribe() method.

Asychronous Observables

Observables can push values asynchronously as well. By calling the asynchronous function setInterval() for example, our observable can push a random number every second indefinitely.

Just like before, our observable will only begin pushing values as soon as the Observable<T>.subscribe() method is called. Unlike before however, Observable<T>.subscribe() will not block while values are being pushed.

The output of our program looks like this:

0.36185343691119787
0.5984572143778477
0.9299556219627905

Process finished with exit code 0

We can also instruct RxJS to execute an observable asynchronously by specifying a scheduler. However that topic is outside the scope of this introductory guide.

Observables are Unicast

By default, observables push a distinct sequence of values to each of its observers. For instance, if two observers subscribe to myObservable they’ll each receive a different sequence of random numbers. This is because the function which generates our random sequence is called for each observer.

The output of our program looks like this:

[observer 1] 0.44351944124845244
[observer 1] 0.6195062881812716
[observer 1] 0.4175168899812369
[observer 2] 0.22031888928039556
[observer 2] 0.8998503335024899
[observer 2] 0.5233304927875606

Process finished with exit code 0

Notice how each observer receives a different sequence of random numbers.

Multicast Observables: Subjects

A subject is a special kind of observable that can push a sequence of values to multiple observers.

Subject<T> is a subclass of Observable<T> which means it implements the subscribe() method. It also complies with the Observer<T> interface, meaning it provides next(), error(), and complete() methods as well.

The output of our program looks like this:

[observer 1] 0.4211932044801445
[observer 2] 0.4211932044801445
[observer 1] 0.866318253814657
[observer 2] 0.866318253814657
[observer 1] 0.6336840485111863
[observer 2] 0.6336840485111863

Process finished with exit code 0

Notice how each observer now receives the exact same sequence of random numbers.

In addition to Subject<T>, there are three specialized subclasses of subject. For a comprehensive list of those subclasses, refer to the documentation here. If you’re an Angular user it’s useful to know that Angular’s EventEmitter<T> class is a also subclass of Subject<T>.

Lastly, we can achieve multicast behavior using Observable<T> by applying either the share or shareReplay operator. However that topic is outside the scope of this introductory guide.

Operators

There are two types of operators. Creation operators, and pipeable operators.

Creation Operators

Creation operators are standalone functions which, as their name suggests, are used for creating observables.

For instance, the of() operator takes an indefinite number of arguments and returns an observable that pushes the value of each of those arguments sequentially.

The output of our program looks like this:

1
2
3
end of sequence

Process finished with exit code 0

For a comprehensive list of creation operators, refer to the documentation here.

Pipeable Operators

Pipeable operators are pure functions which are applied to each value pushed by an observable.

For example, lets create a map() operator which multiplies each pushed value by two.

The output of our program looks like this:

2
4
6

Process finished with exit code 0

One or more pipeable operators can be applied to an observable by passing them to the Observable<T>.pipe() method. This method returns a new observable with each of the supplied operators applied to it.

The output of our program looks like this:

4
6

Process finished with exit code 0

For a comprehensive list of operators, refer to the documentation here.

Further Reading

By now I hope you’re up to speed with the basics of RxJS. For further reading you can refer to rxjs.dev and learnrxjs.io.

Happy coding 🙂