fbpx

In the Javascript world, those that have been working with Angular, would know about Observables and everyone else, they would know Promise. Hence, let’s look at RxJS Observables vs Javascript Promise. This post, examines RxJS Observables and Promises. It does so by first looking at what they are, code samples and where to apply them in an e-commerce app.

The concept of this topic is built around producer vs consumer or you can also think of it as the publisher subscriber model. In this case the producer produces data that can be consumed by a consumer. Please keep in mind, I am using these terms quite loosely here

RxJS Observables

An RxJS observable is a producer which produces values. The official docs define it as a lazy push collection of values. Makes sense? hmm let’s think about this a different way. Think of it as an array of values where the values are pushed to the array periodically i.e. added over time.

Great, how do we create an Observable?

This is not that hard, I mean, have a look at the official RxJS docs and you will just know. However, I reckon this post will be incomplete if I don’t add the code for it here. Let’s say we are talking about a big e-commerce app like Amazon that deals with customer orders. Let’s write an observable that returns customer orders.

import { Observable } from 'rxjs';

const customerOrders = new Observable(subscriber => {
  subscriber.next("Order 1 - Kitchen item");
  subscriber.next("Order 2 - Nintendo Switch Game");
  subscriber.next("Order 3 - Javascript Algorithms book");
  setTimeout(()=> {
    subscriber.next("Order 4 - LG Gram 14 Laptop");
    subscriber.complete();
  }, 3000)
});
function getCustomerOrders() {
  return customerOrders;
}

We have defined our producer above which will emit values for customer orders. What happens in the above code is that we push 3 values (on customer orders) to our array and then after 3 seconds we push a 4th value to it. Contextually, the Observable (publisher) provides details on 3 customer orders to the subscriber and after 3 seconds, info on the 4th order followed by informing the subscriber it is done publishing.

Now let’s see how to subscribe to the Observable to consume the values it publishes,

let orders = getCustomerOrders();
orders.subscribe({
  next(orderStr) { console.log(orderStr);},
  error(err) { console.error(err); },
  complete() { console.log("Orders fetched"); }
});

Our customerOrders is an observable that publishes values and on subscribing to it, it’s subscriber has expect one of three methods.

  • get the value via the next method
  • to know if there’s an error via error method
  • or if the observable is complete i.e. has finished producing values or publisher finished publishing values

We can write the above code in it’s shorter form. Here

customerOrders.subscribe(orderStr => {
  console.log(`Order name ${orderStr});
}, err => {
  console.error(err);
});

When you subscribe to an Observable, you are opening a channel through which you can get a continuous supply of values.

p.s. I will be writing another post on Observables where I will delve into details on next, error and complete methods for an Observable.

Javascript Promise

Ahh promises…good ol promises. A useful mechanism which can carve a road into “callback hell” if not used properly. Promises are still awesome and have their place in code despite the emergence of Observables.

You know how when you make a promise to someone, you are committing to something that you may eventually do (full-fill the promise)? A Javascript promise is a promise in the literal sense. What do I mean? It is function that promises your code that it will eventually return a value (full-fill the promise) and stop or if not, notify your function it cannot. Remember, I mentioned “it may” return a value, so there’s also a chance of it failing and not returning a value in which case it will let you know that an error occured. To summarise it all, a Javascript promise indicates an asynchronous operation that can be completed to return a value or rejected to return an error.

The thing about Promise is that it’s part of the spec. It can be used in Javascript code without any imports, unlike Observables which need to be imported from the RxJS library. You can read more about Promises on MDN.

FYI, I love MDN!!! MDN Web Docs, are my Bible or Bhagavad Gita for all things Javascript 🙂

Let’s look at some code to see how we define promises.

let orderArray = ["Order 1 - Kitchen item",
                "Order 2 - Nintendo Switch Game",
                "Order 3 - Javascript Algorithms book"];

let ordersPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
      orderArray.push("Order 4 - LG Gram 14 Laptop");
      if(orderArray.includes("Order 1 - Kitchen item")) {
        resolve(orderArray);
      } else {
        reject("Missing order");
      }
  }, 2000);
});

How do we consume the values that a promise produces? Let’s see how,

ordersPromise.then(ordersArr => {
  ordersArr.forEach(orderStr => {
    console.log(`Order name ${orderStr}`);
  });
}).catch(err => {
  //log why the promise failed to console
  console.error(err);
});

As you can see consuming a Promise is a one-off. A promise can be created and resolved only once. Notice, how we acquire the values from a promise? via “then” i.e. a callback function. Sometimes, people structure their async Javascript code sequentially. What I mean is, they have X or more promises and each promise depends on the execution of one of the others. So for example something like,

var p1 = new Promise((resolve, reject) => {...});
var p2 = new Promise((resolve, reject) => {...});
var p3 = new Promise((resolve, reject) => {...});
var p4 = new Promise((resolve, reject) => {...});
....
//each promise depends on the other, so to execute it
p1.then(() => {
  let someValFromp1;
  p2.then(() => {
    let someValFromp2;
    p3.then(() => {
      let someValFromp3;  
      p4.then(() => {
        .... 
      })
    })
  })
})

See what I mean? Imagine, trying to debug the resolution of 10 or more promises?

RxJS Observables vs Javascript Promise Github code

You can find all the above source code on Github here and this what the finished code looks like,

Source code for RxJS Observable vs Javascript Promise.
R

RxJS Observables vs Javascript Promise

An observable opens a stream via which it can pass values whereas a promise is full-filled and returns a value only once. What they have in common is that they both deal with asynchronous operations but they do it in different ways.

To some, Observables may seem like a replacement for Promise so should we just not use Promises in our code? I do not think so, promises still have their place. There are certain areas where using promises is still more appropriate than Observables. Let’s have a look at a Scenario, a sample app, some of its problems and see how to best solve those problems.

p.s. a real-time chat app is too obvious a use case for Observables hence I have tried giving a different example here.

Scenario: E-commerce app

Say we have a successful e-commerce app with heaps of customers. (users) and recent focus group studies suggests they want a mobile app. Therefore, we start building a mobile app.

Problem 1: Get existing orders

When the user logs on to the mobile app, they can see the past orders that they placed on the website. Let’s resolve this fetch operation with promises,

const userId = getUserId();
let db = getDatabase();
/** the above lines are just hypothetical */
function getOrders(userId) {
  return new Promise((resolve, reject) => {
    //valid response would be an array of 0 or more orders
    let orders = db.getOrders(userId);
    if(orders) {
      resolve(orders);
    } else {
      reject("Error!Can't find orders, sure about userID?");
    }
  })
}
let ordersForUI = [];
getOrders(userId).then(orders => {
  pastOrders = orders;
}).catch(err => {
  alert(err);
});

Problem 2: Users order the same thing twice

The mobile app became incredibly popular and we introduced a family account which gives all members of the user’s family to buy items. Recently, we found out that members of the family ordered the same items between the mobile and web app. A few users complained that the app should have informed them of what was already ordered so they don’t re-order. This is a synchronisation (real-time update) issue and we can solve it with Observables.

const userId = getUserId();
let orderObservable = getOrdersFromDb(userId);
let ordersForUI = [];
orderObservable.subscribe(order => {
  ordersForUI.push(order);
});

This way we have opened a stream of existing orders from which we get values that we push into the ordersForUI array. With this, whether the are viewing the the data in the mobile app or web app, the list of orders will always be in sync with what’s in the database. This will solve the problem of re-ordering the same items for customers.

p.s. a real-time chat app is too obvious a use case for Observables hence I have tried giving a different example here.

Like the blog? Subscribe for updates

Problem 3: Analysing order data

We have now been operating for a few years and as such have had millions of orders placed with us. We have now hired an analytics team and we want to convert our raw data into meaningful information. The first problem we need to solve is see how well one of our items is selling in a particular region and demographic.

Example

To solve this we need fetch the order history of an item, transform the raw data into the format we need for visualisation. Reading that requirement, it’s kind of obvious that this is a one-off operation, hence let’s solve this with promises.

let db = getDatabase();
function getOrderHistory(item) {
  return new Promise(async (resolve, reject) => {
    //get order history for item
    let orderHistory = await db.getOrderHistory(item);
    if(orderHistory) { 
      resolve(orderHistory);
    } else {
      reject(`Error getting history for: ${item}`);
    }
  })
}
//now to consume get these order history
let orderHistoryForUI = [];
const itemId = getItemId();
 getOrderHistory(itemId).then(history => {
  orderHistoryForUI = history;
 }).catch(err => {
   alert(err);
 });

Makes sense doesn’t it? The above examples show that there’s place for both Observables as well as Promises in Javascript.

Summary

RxJS Observables vs Javascript Promise is worth examining as a lot of organisations still use Javascript Promises and have no intention to change. While Javascript Promise are a solid way of handling asynchronous code, RxJS observables are an alternative worth exploring. They provide a means of exposing data via a stream. So they apply very well in scenarios where we need data in real-time e.g. a chat app or an e-commerce app which needs to show the latest order data.

Like the blog? Subscribe for updates

As usual, if you find any of my posts useful support me by  buying or even trying one of my apps on the App Store. 

https://mydaytodo.com/apps/

Also, if you can leave a review on the App Store or Google Play Store, that would help too.

Categories: Javascript

0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *