Reactive Programming in Javascript using RxJS
Nowadays there is a hype around reactive programming. This article explains the motivation behind learning reactive programming, and the basic concepts to get started.
In this article I use Node.js as a runtime environment for learning RxJS.
Keywords: Node.js, NPM, Javascript, RxJS, Linux, Ubuntu, NVM, ReactiveX, Reactive Programming, Stream, Observable, Observer, Subscription, Operator, Subject, filter, map, pipe, scan, reduce, throttleTime, unsubscribe
DISCLAIMER: THE VIEWS AND OPINIONS EXPRESSED IN THIS ARTICLE ARE THOSE OF THE AUTHOR AND DO NOT REFLECT THE OFFICIAL POLICY OR POSITION OF THE EMPLOYER OF THE AUTHOR. THE ARTICLE IS NOT ENDORSED BY, DIRECTLY AFFILIATED WITH, MAINTAINED, AUTHORIZED, OR SPONSORED BY ANY CORPORATION OR ORGANIZATION. THE INFORMATION CONTAINED ON THIS ARTICLE IS INTENDED SOLELY TO PROVIDE GENERAL GUIDANCE ON MATTERS OF INTEREST FOR THE PERSONAL USE OF THE READER, WHO ACCEPTS FULL RESPONSIBILITY FOR ITS USE. ALTHOUGH THE AUTHOR HAS MADE EVERY EFFORT TO ENSURE THAT THE INFORMATION IN THIS ARTICLE WAS CORRECT AT THE TIME OF THE WRITING, THE AUTHOR DOES NOT ASSUME AND HEREBY DISCLAIM ANY LIABILITY TO ANY PARTY FOR ANY LOSS, DAMAGE, OR DISRUPTION CAUSED BY ERRORS OR OMISSIONS, WHETHER SUCH ERRORS OR OMISSIONS RESULT FROM NEGLIGENCE, ACCIDENT, OR ANY OTHER CAUSE.
Table of Content
The article is divided into the following sections:
- Motivation and basics
- Required knowledge
- What is RxJS?
- Fundamental concepts in RxJS
- Preparation of runtime environment
- Observable, Observer and Subscribe
- Further Observable Creation Possibilities
- Operators: Filter and Map
- About the pipe
- Further operators: scan and reduce
- About throttleTime
- Unsubscription with unsubscribe
- Closer to the web
- Conclusion
- Resources
Motivation and basics
Todays highly interactive web applications and mobile apps the handling of user interface interactions is crucial. We can imagine the UI interactions as a series of events, or in other words, a stream of events. We can think of an event as a piece of information (data), which is available at a certain point in time. For example, a mouse click event happens when the user clicks with the mouse, and the data which is related to this event are the coordinates of the mouse pointer, when the click happens.
There are some fundamental concepts related to reactive programming, which are described in the following chapter.
For this tutorial I use RxJS, which is a Javascript library for reactive programming. Therefore the concepts described in this tutorial are the ones used by RxJS.
Required knowledge
In order to understand this article you need to have at least basic knowledge of the following:
- Javascript
- Node.js
- Node Package Manager (npm)
What is RxJS?
RxJS is a Javascript library licensed under Apache-2.0 License. It is part of ReactiveX, which is a collection of open source projects. On the website of RxJS we can read the following definition.
RxJS is a library for reactive programming using Observables, to make it easier to compose asynchronous or callback-based code. This project is a rewrite of Reactive-Extensions/RxJS with better performance, better modularity, better debuggable call stacks, while staying mostly backwards compatible, with some breaking changes that reduce the API surface. — RxJS (https://rxjs-dev.firebaseapp.com/)
RxJS stands for Reactive Extensions for Javascript.
Fundamental concepts in RxJS
The following concepts are very important to understand if we would like to learn RxJS:
- Stream: A stream is a sequence of data elements made available over time. A stream can be thought of as items on a conveyor belt being processed one at a time rather than in large batches. (Wikipedia)
- Observable: RxJS represents asynchronous data streams using observable sequences. These observable sequences are called Observables. Observables can be used using push or pull patterns. (Source)
- Observer: According to the definition, Observer is an interface for a consumer of push-based notifications delivered by an Observable. An Observer is a consumer of values delivered by an Observable. Observers are objects with three callbacks, one for each type of notification that an Observable may deliver: next, error, and complete. (Source).
- Subscription: Subscribe is an operator. The Subscribe operator is the glue that connects an Observer to an Observable. In order for an Observer to see the items being emitted by an Observable, or to receive error or completed notifications from the Observable, it must first subscribe to that Observable with this operator.
- Operator: Operators are methods that you can use on Observables (and Subjects) that allow you to change the original observable in some manner and return a new observable (Source). Subscribe is an operator.
- Subject: An RxJS Subject is a special type of Observable that allows values to be multicasted to many Observers. While plain Observables are unicast (each subscribed Observer owns an independent execution of the Observable), Subjects are multicast. A Subject is like an Observable, but can multicast to many Observers. (Source)
Further reading:
Observer: https://raw.githubusercontent.com/ReactiveX/rxjs/master/doc/observer.md
Subject: https://github.com/ReactiveX/rxjs/blob/master/doc/subject.md
Preparation of runtime environment
As the runtime environment for the examples I use Ubuntu 14.04.5 LTS (trusty)
. I used Node.js version v6.11.2
. My NPM version is 3.10.10
. I assume that Node.js and npm is already installed in your system, and a new folder was created for these rxjs examples. In my system I named this folder workspace
.
(In my system, Node Version Manager (nvm) is also installed (version 0.31.0
). NVM is a powerful tool to manage multiple Node.js versions in your development environment. for further info about NVM you can check for example https://nodesource.com/blog/installing-node-js-tutorial-using-nvm-on-mac-os-x-and-ubuntu/)
The following steps are required to initialize our runtime environment:
- initalize the folder by generating a new
package.json
file (The reason behind creating this file can be read at https://docs.npmjs.com/creating-a-package-json-file):
npm init -y
After this we see the following:
2. install RxJS and other dependencies with the following command:
npm install rxjs
After this step our folder looks like the following:
The folder node_modules
contains the installed Node.js modules.
3. Test if RxJS is really working. This is done by our first simple Javascript which looks like the following:
You can copy-paste this code to your own file, by starting the nano
editor from the console:
nano rxjs-helloworld.js
In nano, you can save the file by pressing CTRL+O
and ENTER
. You can exit from nano by pressing CTRL+X
.
To run the script you can use the following command:
node rxjs-helloworld.js
Or, if you don’t have the current directory in your path, you need to use
node ./rxjs-helloworld.js
The output looks like the following:
With this we have prepared our environment for trying out RxJS. The Hello World example will be explained later in this article. Remember that you can always run your code with
node my_script.js
Observable, Observer and Subscribe
Let’s look at the first example we have already seen.
In this example
- We define an observable with
Observable.create()
. In the input of this function call we specify a callback function, which receivesobserver
as the parameter, and calls functions on this. Thenext
function is called 3 times, and thecomplete
function once. - Then we call
subscribe
method of the observable.
The Observer has 3 methods:
- next: The callback to receive notifications of type
next
from the Observable, with a value. - error: The callback to receive notifications of type
error
from the Observable, with an attached Error. (More info about the error object here) - complete: The callback to receive a valueless notification of type
complete
from the Observable.
In the subscribe method of the observable we specify 3 callback functions as parameters. The first one is called when the next data is emitted by the observable, the second one is called when an error occurs, the third one is called when the observer completes its job, and there was no error.
The subscribe can be called also in different way, by specifying an object with 3 properties, like the following:
Further Observable Creation Possibilities
Observables can be created from different objects.
In the following example, observable is created out of an array of numbers.
Here, in case of specifying this callback function in the subscribe, we could also say:
observableFromArray.subscribe({
next: function(value) { console.log(value); }
});
It’s also fine that we don’t specify the error
and the complete
attributes.
We can convert strings as well.
We can create observable from events as well. For this, in Node environment, we need an event emitter. (Node.js contains event emitters by default, you can read more about this here.)
Operators: filter and map
Observables can be transformed to other Observables. This can be done by using operators. Examples of operators:
from
fromEvent
filter
map
There are plenty of operators, the list can be found here.
In the following example, filter
call filters out the even numbers from the stream, and returns a stream which contains only the odd numbers x % 2
will be 0 in case of even numbers, and 1 in case of odd numbers. 1 is truthy, therefore the odd numbers will remain in the stream. After this we subscribe to the stream to print it out to the console.
We enhance this example by a map function, which doubles the emitted numbers:
The output of this second example will be:
Next: 2
Next: 6
Next: 10
Next: 14
Next: 18
About the pipe
In the above examples we used pipe()
. In RxJS operators are pure functions. This means that they can be chained, and this chaining is done by using pipe()
function on the observable. More info about piping can be found here.
Further operators: scan and reduce
The signature of scan
operator looks like the following:
scan(accumulator: function, seed: any): Observable
Scan will call the accumulator function on the values over time, starting with value of seed
as a basis.
In this example we calculate the factorial of numbers from 1 to 10.
The output is:
1
2
6
24
120
720
5040
40320
362880
3628800
Reduce is something similar, but it reduces the values to a single value in each call.
The output is: 3628800
About throttleTime
The definition of throttleTime()
is quite simple: Emit latest value when specified duration has passed (source). What does this mean?
The result of the above code will be the following:
0
2
4
6
8
10
12
14
16
18
20
22
24
<...and the sequence goes on>
The interval(500)
method emits a value every 500 milliseconds. The throttleTime(1000)
method gets the latest value from the sequence every 1000 milliseconds (=1 second).
Unsubscription with unsubscribe
Let’s enhance the above example with an unsubscribe()
call:
This will result in:
0
2
4
6
8
10
12
14
16
18
After 10 seconds the sequence stops.
Closer to the web
The last example below uses an HTML page with Javascript to try RxJS. The page shows a button, and when you click the button, it will show the current time. For this example I used another JS library: moment.js, for converting the time to the format I would like to see.
I also put this on Codepen so that you can try it.
Conclusion
This was a quick overview of RxJS, which definitely worth to dig deeper in it. It absolutely makes sense these days to learn it.
I hope you learned something new today. If you have any questions please leave a comment.
Resources
There are plenty of resources on the web regarding reactive programming. For this tutorial I used the following:
- The introduction to Reactive Programming you’ve been missing: https://gist.github.com/staltz/868e7e9bc2a7b8c1f754