RxJS Tips - JavaScript Promises and Observables
By: Wandering Developer
Tags: Rxjs, Asyncawait, Reactive Programming, Javascript Development

Worlds Collide — Putting it Together

Now that you’re up to speed with the concepts, you may be wondering what they have to do with each other? After all, Observables and Promises both solve completely different problems.

To help illustrate why you might want to do this, I’ve created a “Problem Definition”. This real-world example demonstrates why this technology might be useful, and perhaps you could see how it can apply to your own work.

The Problem

A website wishes to display live Stock Ticker data. When the site loads, the data must be immediately available from a cache. The data should update every 60 seconds, but, on a connection error, always return from the cache. If the user hits the refresh button, the data should be refreshed immediately. The UI should be notified on a connection error to inform the user that the data isn’t Live.

This doesn’t sound like a complicated problem, but, when you dig into all of the different states, especially with the error handling, without planning this code can get out of hand quickly.

To tackle, let’s break it down.

From the above statement, there are 4 potential data sources for the UI:

Stock Ticker Data — Live or Cached

— Live or Cached Is Live Data — True if data is live, otherwise False

— True if data is live, otherwise False Is Refreshing — True if data is currently refreshing, otherwise False

— True if data is currently refreshing, otherwise False Error Message — If the data isn’t live, an associated error message

And, in addition to the 4 data sources for the UI, there is an additional input command, “Refresh” which will interrupt the Timer.

As a bonus point, the refresh button should not be enabled when manual refreshing is occurring, to prevent double-clicks.

So, without further ado, I present the design for our new, highly polished application.

Another example of why I’m not a designer…

So … moving on.

As the data is going to come from 2 places, we need the following API’s:

Angular Http Client — Used for fetching the data (Observable-based) CacheStorage API — Used to store the result, and fetch in the event of an error (Promise-based)

The immediate challenge is that these API’s conform to different standards.

To help illustrate the solution, I’m going to break this down into the following chunks:

Interval to return the Stock Data with Refresh Saving the Stock Data into the cache Setting the Boolean States Error Handling

I’m going to be building this using Angular 10 but the concepts will apply to whatever Framework you’re comfortable with.

From the screenshot above, the layout is defined as follows:

As you can see, our HTML is monitoring 4 observables that represent the state of the application. The price will be updated automatically when the data stream changes and the other <span> and <strong> tags will display as necessary. In addition, the Refresh Button is disabled automatically when appropriate, and the request command is fired on the (click) event.

Step 1 — Stock Data Observable

The first task is to create the simple Stock Data Observable. Now, because a good, free, open Stock Ticker API isn’t available I’m going to cheat slightly and use an online random number generator. However, the effect is still the same.

The ticker observable will be the primary pipeline for the entire application, where all other state variables will seed their values from.

The value for this observable will be updated from 3 sources:

When the application loads Every 60 seconds When the refresh button is tapped

To do this, we need to create a “seed”. Using the merge() RxJS operator we are able to create an Observable that uses the values from all 3 sources and will fire when any of them emits a value. We aren’t interested in the value returned from merge() and are merely using it to kick-start the process.

The code demonstrates a really simple 2-stage pipeline that, when triggered, fetches the Stock Ticker price and parses it to a number.

However, the magic is in the seed$ value. By using the merge combinational operator, the pipeline will start for any of the 3 triggers.

Step 1 — In the Bag

So, that’s Step 1 complete, on to Step 2.