RxJS Essentials. Part 3: using Observable.create()

In this article I’ll show you how to create an Observable using the method create() and how an observable can send messages to the observer using its API. The previous articles in this series include:

1. Basic Terms
2. Operators map, filter, and reduce

An observer is an object that implements one or more of these functions: next(), error(), and complete(). Let’s use an object literal to illustrate an observer, but later in this section, we’ll use a simplified syntax with arrow functions:

const beerObserver = {
  next: function(beer) { console.log("Subscriber got " + 
                       beer.name)},
  error: function(err) { console.err(error)},
  complete: function() {console.log("The stream is over")}
}

You can create an observable with the method create() passing an argument that will represent an observer. When observable gets created, it doesn’t know yet which concrete object will be provided. It’ll be known later, at the time of the subscription.

beerObservable = Rx.Observable.create( 
                 observer => observer.next(beer));

This particular observable thinks, “When someone will subscribe to my beers, they will provide me a concrete beer consumer, and I’ll just push one beer object to this guy”.

At the time of subscription, we’ll provide a concrete observer to our observable.

beerObservable.subscribe(beerObserver); 

The observer will get the beer and will print on the console something like this:

Subscriber got Stella

The next listing has a complete script that illustrates the creation of the observer, observable and the subscription. The function getObservableBeer() creates and returns the observable that will iterate through the array of beers and will push each beer to the observer by invoking next(). After that, our observable will invoke complete() on the observer indicating that there won’t be any more beers.

function getObservableBeer(){
        
    return Rx.Observable.create( observer => { // 1

      const beers = [
        {name: "Stella", country: "Belgium", price: 9.50},
        {name: "Sam Adams", country: "USA", price: 8.50},
        {name: "Bud Light", country: "USA", price: 6.50},
        {name: "Brooklyn Lager", country: "USA", price: 8.00},
        {name: "Sapporo", country: "Japan", price: 7.50}
      ];

       beers.forEach( beer => observer.next(beer)); // 2

           observer.complete(); // 3
       }
    );
}

getObservableBeer()
     .subscribe(  // 4
         beer => console.log("Subscriber got " + beer.name),
         error => console.err(error),
            () => console.log("The stream is over")
);

1 Create and return the observable object
2 Push each beer to the observer
3 Push the end of stream message to the observer
4 Subscribe to the observable providing the observer object in the form of three fat arrow functions.

The output of this script is shown next:

Subscriber got Stella
Subscriber got Sam Adams
Subscriber got Bud Light
Subscriber got Brooklyn Lager
Subscriber got Sapporo
The stream is over

The RxJS 5 version of this code sample is here. The RxJS 6 version is here.

In our code sample we were invoking next() and complete() on the observer. But keep in mind, that there an observable is just a data pusher, and there is always a data producer (an array of beers in our case) that may generate an error. In this case, we’d invoke observer.error() and the stream completes. There is a way to intercept an error on the subscriber’s side to keep the streaming alive and will discuss it in one of the future articles of this series.

It’s important to note, that our data producer (the array of beers) is created inside the observable getObservableBeer(), which makes it a cold observable. A WebSocket could be another example of the producer. Imagine you have a database of beers on the server, and you can request them over a WebSocket connection (could use HTTP or any other protocol here):

Rx.Observable.create((observer) => {
  const socket = new WebSocket('ws://beers');
  socket.addEventListener('message', (beer) => observer.next(beer));
  return () => socket.close(); // is invoked on unsubscribe()
});

With cold observables each subscriber will get the same beers regardless of the time of the subscription provided that the query criteria (in our case show all beers) are the same.

Many RxJS tutorials explain concepts just using observables that emit numbers, which sometimes complicates the understanding of the concept. Things are different when we use examples from the real life. Everyone understands what the beer is for so the concepts become clear, right? In the next article, you’ll get familiar with the RxJS Subject.

If you have an account at O’Reilly’s safaribooksonline.com, you can watch my video course “RxJS Essentials” there.

Advertisements

RxJS Essentials. Part 2: map, filter, reduce

In the previous article, I introduced the main players or RxJS, and now let’s start getting familiar with RxJS operators. In this article well use the operators map(), filter(), and reduce().

As the data elements flow from the observable to the observer, you can apply one or more operators, transforming each element prior to supplying it to the observer. Each operator takes an observable as an input, performs its action, and returns a new observable as an output:

Since each operator takes an observable in and creates an observable as its output, operators can be chained so each observable element can go through several transformations prior to being handed to the observer.

RxJS offers about a hundred of various operators, and their documentation may not always be easy to understand. On the positive side, the documentation often illustrates operators with so called marble diagrams. You can get familiar with the syntax of marble diagrams here.

The map() operator

The map() operator transforms one value to another. It takes a given value from the observable stream and applies the provided transforming function to it.

The marble diagram below is taken from the RxJS manual, and it illustrates the map() operator. This diagram shows the map() operator that takes a value of each incoming element and multiplies it by 10. The fat arrow function x => x*10 is the transforming function in this example.

On top, a marble diagram shows the horizontal line with several shapes representing a stream of incoming observable elements. Then goes the illustration of what a particular operator does. At the bottom, you see another horizontal line depicting the outgoing observable stream after the operator has been applied. The vertical bar represents the end of the stream. When you look at the diagram, think of a time that’s moving from left to right. First, 1 was emitted, the time went by… and 2 was emitted, the time went by… and 3 was emitted, and then the stream ended.

The filter() operator

Now let’s get familiar with the marble diagram of the filter() operator shown next.

The filter() operator takes a function predicate as an argument, which returns true if the emitted value meets the criteria, or false otherwise. Only the values that meet the criteria will make it to the observer. This particular diagram uses the fat arrow function that checks if the current element is an odd number. The even numbers won’t make it further down the chain to the observer.

The following code sample declares an array of beers and turns it into Observable using the Observable.from() function. Then it applies the filter() operator to pass only the beers that cost less than eight dollars, and the chained map() operator converts the beer object into a string.

let beers = [
    {name: "Stella", country: "Belgium", price: 9.50},
    {name: "Sam Adams", country: "USA", price: 8.50},
    {name: "Bud Light", country: "USA", price: 6.50},
    {name: "Brooklyn Lager", country: "USA", price: 8.00},
    {name: "Sapporo", country: "Japan", price: 7.50}
];

Rx.Observable.from(beers)   // <1>
  .filter(beer => beer.price < 8)   // <2>
  .map(beer => beer.name + ": $" + beer.price) // <3>
  .subscribe(    // <4>
      beer => console.log(beer),
      err => console.error(err),
      () => console.log("Streaming is over")
);

console.log("This is the last line of the script");

1. Turn the beers array into an Observable

2. Filter out the beers that are more expensive than eight dollars

3. Turn the object into a string showing the beer name the price

4. Subscribe to the Observable providing the Observer as three fat arrow functions

This program will print the following on the console:

Bud Light: $6.5
Sapporo: $7.5
Streaming is over
This is the last line of the script

To see it in action in CodePen, follow this link.

By default, the operator from() returns a synchronous observable, but if you want an asynchronous one, use a second argument specifying an async scheduler:

Rx.Observable.from(beers, Rx.Scheduler.async)

Making this change in the above code sample will print “This is the last line of the script” first and then will emit beers info.

Don’t include the entire RxJS library in your app

When you’ll be reviewing the code in CodePen, not that the HTML document imports the entire RxJS library as follows:

<script 
 src="https://unpkg.com/@reactivex/rxjs/dist/global/Rx.js">
</script>

This loads the entire RxJS library even though we only use the Observable, from(), filter(), and map(). Loading the entire library for demo purposes is OK, but in the real-world apps, we want to minimize the app size and load only the code we actually use. For example, in JavaScript or TypeScript apps we’d install RxJS locally and write something like this:

import 'rxjs/add/operator/map';
import {Observable} from "rxjs/Observable";

Including the entire RxJS add about 90KB (33KB gzipped) to your app that uses RxJS. The size of the future version RxJS 6 will be substantially smaller, but we recommend including only the classes and functions that you use for now.

NOTE. Starting from RxJS 5.5 you can (and should) use so-called pipeable operators, which are tree-shaking-friendly and simplify import statements, e.g.

import { debounceTime, map} from 'rxjs/operators';

Using this syntax also simplifies the tree-shaking process performed during app bundling with the tools like Webpack or Rollup.

The reduce() operator

Now we’d like to introduce the operator reduce() that allows you aggregate values emitted by an observable. The marble diagram of the reduce() operator is shown next. This diagram shows an observable that emitted 1, 3, and 5, and the reduce() operator added them up producing the accumulated value of 9.

The operator reduce() has two arguments: an accumulator function where you specify how to aggregate the values, and the initial (seed) value to be used by the accumulator function. The above diagram uses zero was as an initial value, but if we’d change it to 10, the accumulated value would be 19.

As you see from the above diagram, the accumulator function also has two arguments:

* acc stores the currently accumulated value, which is available for each emitted element

* curr stores the currently emitted value.

The following code sample creates an observable for the beers array and applies two operators to each emitted element: map() and reduce(). The map() operator takes a beer object and extracts its price, and the reduce() operator adds the prices.

let beers = [
    {name: "Stella", country: "Belgium", price: 9.50},
    {name: "Sam Adams", country: "USA", price: 8.50},
    {name: "Bud Light", country: "USA", price: 6.50},
    {name: "Brooklyn Lager", country: "USA", price: 8.00},
    {name: "Sapporo", country: "Japan", price: 7.50}
];

Rx.Observable.from(beers) 
    .map(beer =>  beer.price)  // <1>
    .reduce( (total,price) => total + price, 0)  // <2>
    .subscribe(
        totalPrice => console.log(`Total price: ${totalPrice}`)  // <3>
);

1. Transform the beer object into its price
2. Sum up the prices
3. Print the total price of all beers

Running this script will produce the following output:

Total price: 40

In this script, we were adding all prices, but you could apply any other calculation to create a different aggregate value, e.g. to calculate an average or maximum price.

The reduce() operator emits the aggregated result when the observable completes. In the above example, it happened naturally, because we created an observable from an array with a finite number of elements. In other scenarios, you’d need to invoke the method complete() on the observer explicitly, and you’ll see how to do it in the next article of this series.

To see this example running in CodePen follow this link.

Code samples from this article were turning the array into an observable and were magically pushing the array’s elements to the observer. In the next article, I’ll show you how to push elements by invoking the next() function on the observer.

If you have an account at O’Reilly’s safaribooksonline.com, you can watch my video course “RxJS Essentials” there.

RxJS Essentials. Part 1: Basic terms

Today, I’m starting a series of articles about programming with reactive extensions. This series is about the JavaScript RxJS library, but in the future, I’m planning to write a similar series about the RxJava – one of the Java versions of reactive extensions.

The first library of reactive extensions (Rx) was created by Erik Mejier in 2009. Rx.Net meant to be used for the apps written using the Microsoft’s .Net technology. Then the Rx extensions were ported to multiple languages, and in the JavaScript world, RxJS 5 is the current version of this library.

Let’s see what being reactive means in programming by considering a simple example.

let a1 = 2;

let b1 = 4;


let c1 = a1 + b1;  // c1 = 6

 

This code adds the values of the variables a1 and b1, and c1 is equal 6. Now let’s add a couple of lines to this code modifying the values of a1 and b1:

let a1 = 2;

let b1 = 4;


let c1 = a1 + b1;  // c1 = 6

 

a1 = 55;       // c1 = 6 but should be 59 
    
b1 = 20;       // c1 = 6 but should be 75

While the values of a1 and b1 changed, c1 didn’t react to these changes and its value is still 6. Of course, you can write a function that adds a1 and b1 and invokes it to get the latest value of c1, but this would be an imperative style of coding where you dictate when to invoke a function to calculate the sum.

Wouldn’t it be nice if c1 would be automatically recalulated on any a1 or b1 changes? Think of any spreadsheet program like Microsoft Excel, where you could put a formula =sum(a1, b1) into the c1 cell, and c1 would react immediately on the changes in a1 and b1. In other words, you don’t need to click on any button to refresh the value of c1 – the data are pushed to this sell.

In the reactive style of coding (as opposed to imperative one), the changes in data drive the invocation of your code. Reactive programming is about creating responsive event-driven applications, where an observable event stream is pushed to subscribers, which observe and handle the events.

In software engineering, Observer/Observable is a well-known pattern, and it’s a good fit in any asynchronous processing scenario. But reactive programming is a lot more than just an implementation of the Observer/Observable pattern. The observable streams can be canceled, they can notify about the end of a stream, and the data pushed to the subscriber can be transformed on the way from the data producer to the subscriber by applying one or more composable operators (you’ll see some of them in Part 2 of this series).

Getting familiar with RxJS terminology

We want to observe data, which means that there is some data producer that can be a server sending data using HTTP or WebSockets, a UI input field where the user enters some data, an accelerometer in a smart phone, et al. An observable is a function (or an object) on the client that gets the producer’s data and pushes them to the subscriber(s). UI An observer is an object (or a function) that knows how to handle the data elements pushed by the observable.

Hot and cold observables

There are two types of observables: hot and cold. The main difference is that a cold observable creates a data producer for each subscriber, while a hot observable creates a data producer first, and each subscriber gets the data from one producer starting from the moment of subscription.

Let’s compare watching a movie on Netflix vs going into a movie theater. Think of yourself as an observer. Anyone who decided to watch “Mission Impossible” on Netflix will get the entire movie regardless of when he or she hit the button play. Netflix creates a new producer to stream a movie just for you. This is a cold observable.

If you go to a movie theater and the showtime is 4PM, “the producer is created” at 4PM and the streaming begins. If some people (subscribers) were late to the show, they missed the beginning of the movie and will watch it starting from the moment of arrival. This is hot observable.

A cold observable starts producing data when some code invokes a subscribe() function on it. For example, your app may declare an observable providing a URL on the server to get certain products. The actual request will be made only when you subscribe to it. If another script will make the same request to the server, it’ll get the same set of data.

A hot observable produces data even if there are no subscribers interested in the data. For example, an accelerometer of your smartphone produces multiple data about the position of your device even if there no app that subscribes to this data. Or a server can produce the latest stock prices even if no user is interested in this stock.

The main players of RxJS

The main players of RxJS are:

* Observable – data stream that pushes data over time
* Observer – consumer of an observable stream
* Subscriber – connects observer with observable
* Operator – a function for the en-route data transformation

I’ll introduce each of these players in this series by showing examples of their use. For a complete coverage, refer to RxJS documentation.

Observable, observer, and subscriber

As stated earlier, an observable gets data from some data source (a socket, an array, UI events) one element at a time. To be precise, an observable knows how to do three things:

* Emit the next element to the observer
* Throw an error on the observer
* Inform the observer that the stream is over

Accordingly, an observer object provides up to three callbacks:

* The function to handle the next element emitted by the observable
* The function to handle errors thrown by the observable
* The function to handle the end of stream

The subscriber connects an observable and observer by invoking the method subscribe() and disconnects them by invoking unsubscribe(). A script that subscribes to an observable has to provide the observer object that knows what to do with the produced elements. Let’s say we created an observable represented by the variable someObservable and the observer represented by the variable myObserver. Then you can subscribe to such an observable as follows:

let mySubscription: Subscription = someObservable.subscribe(myObserver);

To cancel the subscription, invoke the unsubscribe() method:

mySubscription.unsubscribe();

How an observable can communicate with the provided observer? It does it by invoking the following functions on the observer object:

* next() to push the next data element to the observer

* error() to push the error message to the observer

* complete() to send a signal to the observer about end of stream

You’ll see an example of using these functions in the next article of this series.

Creating observables

RxJS offers multiple ways of creating an observable depending on the type of the data producer. As an example, the data producer a DOM event, a data collection, a custom function, a WebSocket and more. Below are some examples of the API to create and observable:

* Observable.of(1,2,3) – turns the sequence of numbers into an Observable
* Observable.create(myObserver) – returns an Observable that can invoke
 methods on myObserver that you will create and supply as an argument
* Observable.from(myArray) – converts an array represented by the variable myArray into an Observable. You can also use any an iterable data collection or a generator function as an argument of from().
* Observable.fromEvent(myInput, ‘keyup’) – converts the keyup event from some HTML element represented by myInput into an Observable
* Observable.interval(1000) – emits a sequential integer (0,1,2,3…) every second

Let’s create an observable that will emit 1,2, and 3 and subscribe to this observable:

Rx.Observable.of(1,2,3) 
    .subscribe(
        value => console.log(value),
        err => console.error(err),
        () => console.log("Streaming is over")
);

Note that we pass three fat arrow functions to subscribe(). These three functions are the implementation of our observer. The first function will be invoked for each element emitted by the observable. The second function will be invoked in case of an error providing the object representing the error. The third function takes no arguments and will be invoked when the observable stream is over. Running this code sample will produce the following output on the console:

1
2
3
Streaming is over

To see it in action in CodePen, follow this link. Open the console view at the bottom to see the output.

The basic terms are covered. In the next article of this series, I’ll introduce you to some RxJS operators that are used to transform the emitted items while they’re moving from observable to the observer.

If you have an account at O’Reilly’s safaribooksonline.com, you can watch my video course “RxJS Essentials”.