RxJS 101: Simple Analogy for RxJS Concepts
Tags: javascript, webdev, beginners, angular
Published: 2020-04-13 17:20:49

Hey there, fellow devs! Today I will be talking about something that I am finally able to tick off my to-do list just recently -- understanding RxJS concepts!

Ever since I started my journey as an Angular Developer, RxJS has been that topic which I can't wrap my head around. I know how to use it (maybe not correctly). I also know how to make it work. But if someone asked me what an Observable is and what the subscribe function does, I'll probably say something like, "An observable is the return type for HTTP calls, and you subscribe to it to retrieve the data." It's not technically wrong in Angular's perspective, but it's shallow, and it doesn't explain the whole idea correctly.

Now, I will try to explain the main concepts of RxJS and how to use it. My attempt will be divided into three parts:
* [Analogy Explanation](#analogy)
* [Code Example](#practical)
* [Summary](#summary)

Note that RxJS is a huge topic with complex concepts. This post is created to understand the foundation of RxJS: Observables, Observers and Subscribers (and also a bit of Operators). If you're trying to learn the basics, this article is for you.

Let's start!

## **Analogy Explanation** <a name="analogy"></a>
The formal definition in the RxJS website is difficult to digest, so here's an analogy to facilitate our understanding. 

![Sushi Train GIF](https://j.gifs.com/YWNG4M.gif)
### **RxJS is like a Sushi train restaurant.**

The restaurant has the following routine:
1. The chef prepares the ingredients needed for the items in the **Restaurant Menu**, which *creates the basic food item (ie. Sushi)*.

2. A customer enters the restaurant, gets a table, selects the **Order** in the kiosk and submits it.

3. A chef will receive the order items and will proceed to its preparation. Depending on the order, **he might add a drink or some side dishes with the sushi,** according to the customer's request.

4. Once the chef finishes preparing the order, a **Restaurant Staff** will then *handle* the delivery of the order through the sushi train. The order will be *complete* when the train successfully delivers the order to the correct table. In case the staff committed a *mistake* in specifying the destination of the order, the **Restaurant staff** will then handle the order to be delivered to the correct table.

5. Just in case the customer decides to eat somewhere else, **canceling** orders are allowed. 

The events mentioned above are what the **Sushi Train Restaurant** is built upon. Without these processes, the restaurant cannot function.

### And now you may wonder, how does this relate to RxJS?


1. The **Restaurant Menu** represents an __*Observable*__. It is an idea of an invocable collection. None of the items on the menu are given yet to the customer, but it is ready to be delivered or invoked.

2. The **Order** represents a __*Subscription*__. It is the execution of the Menu Item, which represents the Observable. The Menu Item will stay in the kitchen unless a customer *orders* it. In the same way, an Observable will only be executed if it is subscribed upon.

3. The **process of assembling the order** represents the __*Operators*__. A Menu Item can be transformed and combined with other menu items before it is delivered as an order. RxJS Operators are functions that do the same to a collection of data or events.

4. The **Restaurant Staff** is the __*Observer*__. He literally observes the menu items that were prepared and knows what to do when the *next* item arrives, when an *error* occurs during delivery and when the item is successfully *completed*. An Observer listens to the values of the Observable and handles it according to its collection of callbacks (next, error, complete).

5. And lastly, the __*cancellation of order*__ represents the unsubscription. 

RxJS is like a **Sushi Train Restaurant**. In its core is the Restaurant Menu (Observable), while other elements such as Orders (Subscription), Restaurant Staff (Observer), Chef and Customers play their part to achieve an asynchronous and event-based process.


## **Code Example** <a name="practical"></a>
By now you might be thinking, "Well, I finally get the concept, but I don't know how to apply it in my code!" Say no more, fam. I gotcha.

#### Let's look at this simple Observable that we created using the *creation function* `of` in RxJS.

```javascript
    const restaurantMenu$ = of('Tuna Roll', 'Egg Roll', 'Salmon Roll');
    const order = restaurantMenu$
      .subscribe({
          next(item) { console.log('Order: ' + item); },
          error(err) { console.error('Failed to deliver order: ' + err); },
          complete() { console.log('Order Complete'); }
      });

    /** Code output: 
    Order: Tuna Roll
    Order: Egg Roll
    Order: Salmon Roll
    Order Complete
    **/
```
So what do we have here?
* **Observable** is the `restaurantMenu$`
* **Subscription** is the `order`
* **Observer** is the `object` passed to the subscribe function. The Observer knows what to do when an item is *emitted* from the Observable, when it *errors* and *completes*.

In the output of the code above, we didn't see the *'Failed to deliver order: '* log because no error occurred. It is also important to note that a subscription can end in three ways:
1. `unsubscribe()` - cancel the execution of the Observable
2. `complete()` - stops the Observable and can only happen if there was no error
3. `error()` - happens if an error occurred, stops the Observable (complete won't be triggered).

Let's say there was a mistake while delivering the second item, the Egg Roll? Will it still proceed to emit the third item (Salmon Roll)? *The answer is no*. The Observable stops when an error is encountered. That's why it is important to make sure you handle it in your code, but for the sake of simplicity, we won't discuss techniques to handle errors here.

So far, we have already shown the three concepts. How about **Operators**? How do we use it?

#### Let's say that for a day, the restaurant gives a free drink promo to all orders. How will we do that? Let's look at this code:

```javascript
    const restaurantMenu$ = of('Tuna Roll', 'Egg Roll', 'Salmon Roll')
      .pipe(
        map(item => item + ' with Free Drink')
      );
    const order = restaurantMenu$
      .subscribe(orderItem => console.log('Order: ' + item ));

    /** Code output: 
    Order: Tuna Roll with Free Drink
    Order: Egg Roll with Free Drink
    Order: Salmon Roll with Free Drink
    **/
```
#### There are two things that changed. Let's talk about the `$restaurantMenu$` Observable. 

Since we wanted each item to come with a free drink, we will have to **pipe** through a **set of operations** so we can transform the item. We do this through **Operators**. In the code above, we used the `map` operator to transform each item with a free drink included. 

There are actually two types of Operators. *Pipeable Operators and Creation Operators*. In the code shown above, we added a Pipeable Operator. This kind of operator is used through the syntax of `observableInstance.pipe(operator())`. Creation Operators are the other kind of operator, which can be called as standalone functions to create a new Observable. An example of this is the function `of` which we used in code.

Note that Observables are *lazy*. This means that when we created it through the `of` function with a pipe of operations, it will not be executed upon initialization. As I said earlier, it will only be executed when you subscribe to it. This is also one of its difference with Promises, which is executed as soon as it is defined.

#### Now, let's move on to the `order` Subscription.

Compared to our previous example, the **Observer** has been reduced to only one line: `orderItem => console.log('Order: ' + item )` but it still worked. This is because the **next()** function is the only required function while error() and complete() is optional. If you only pass one function, it will be assumed as the `next()` callback function.

You can also see that in our result log, there is no 'Order Complete' log. Since we didn't define what the Observer should do when it completes, it did nothing upon completion.

We have tackled Observables, Observer, Subscription and Operators. Yay! But wait, isn't it weird that the order returns all the items in the `restaurantMenu$`? What if the customer only ordered a Salmon Roll? The Observable should only emit the said item.

#### Let's try to do that by using the `filter` operator.
```javascript
    const restaurantMenu$ = of('Tuna Roll', 'Egg Roll', 'Salmon Roll')
      .pipe(
        map(item => item)
      );
    const order = restaurantMenu$
      .pipe(
        filter(item => item === 'Salmon Roll')
      )
      .subscribe(orderItem => console.log('Order: ' + orderItem));

    /** Code output: 
    Order: Salmon Roll
    **/
```
Here, we filtered the menu with the corresponding order item, 'Salmon Roll'. Normally you will filter it by ID since the name itself is possible to be transformed somewhere else and you won't have a match. But since this is a simple example and we only emit strings from the Observable instead of an object, we didn't use an ID filter. 

That's it! We talked about the basic concepts in RxJS. Before we end this article, let's summarize what we learned.

## Summary <a name="summary"></a>
* **RxJS** is a library for composing asynchronous and event-based programs by using observable sequences. We can think of it as a *Sushi Train Restaurant*.
* An **Observable** is a collection that is waiting to be invoked, with future values or events. Much like a *Restaurant Menu*.
* A **Subscription** is an execution of an Observable, like an *Order* to a Menu item.
* An **Observer** is a collection of callbacks that knows how to listen to values delivered by the Observable. These callbacks are the `next()`, `error()`, `complete()` methods. It works like a *Restaurant staff* which knows what to do with the orders.
* **Operators** are functions that are used for manipulating the Observable. We can think of it as the *process of assembling the order*. There are two types: Pipeable and Creational.
* An Observable can be stopped by unsubscribing or through the `error()` and `complete()` callbacks.
* Observables are lazy, they don't execute until subscribed upon.

There you go. I hope this article helped you in understanding the basics of RxJS. Thanks for reading!