An Introduction to Observables for Angular Developers

When developing mobile apps and web sites, we often use observables to populate the UI of our app with external data, asynchronously. In this article, we’re going to learn about the concept of the Observable: what they are, why we prefer them to other methods of handling data, how RxJS works within this context, and some real world examples of where they are used.

What are Observables?

It’s easy enough to find descriptions of observables, including excellent deep dives covering their use within Functional Reactive methods of programming. I’d like to take a step back from these deeper dives and explain a bit why we need to understand observables as Angular and/or NativeScript developers.

So, what are observables?

In the Angular docs, they are described as a sort of array:

You can think of an observable as an array whose items arrive asynchronously over time. Observables help you manage asynchronous data, such as data coming from a backend service. Observables are used within Angular itself, including Angular’s event system and its http client service. To use observables, Angular uses a third-party library called Reactive Extensions (RxJS). Observables are a proposed feature for ES 2016, the next version of JavaScript.

These jargon-laced descriptions may actually raise more questions than they answer. The big question, in my opinion, is this: observables help you manage asynchronous data…but why do we have to have some secret sauce to help us do that? Aren’t promises enough? I mean, we used to use Ajax, for cryin’ out loud, and it was FINE, right?

Cooking with JavaScript

Well, as JavaScript developers know, there are some interesting particularities to this quirky language. One of the major ones is that JavaScript, by design, is single-threaded. That makes handling asynchronous data streams a little challenging. The way it works is by means of an Event Loop, which is well-explained here. In brief:

  • Each line of a JavaScript program processes synchronously within a Call Stack. If you need a visual, think of the Call Stack as the soup pot in which elements are progressively added to build up a browser-based program.
  • If any of the elements within the Call Stack are written as asynchronous callback functions – that is, they aren’t intended to be processed until later – that function is then placed in an Event Table, where it is queued for processing (e.g. put back into the Call Stack) later. The Event Table is like a cutting board where JavaScript functions are readied for future processing.
  • The process that checks whether an event is ready to be moved out of the Event Table and into the Call Stack for processing is called the Event Loop. The Event Loop is like a chef, ushering functions from Table to Stack (from cutting board to soup pot). Leveraging this model of “parking” asynchronous functions in the Event Table stops code from blocking the browser by continuing its process of processing the data and displaying it, as the Event Loop handles automatically pushing processable functions back to the Call Stack.


Single threading is actually a good idea…

Observables, then, help JavaScript as a language integrate the observer design pattern:

The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods. It is mainly used to implement distributed event handling systems.

Evolving Async

As JavaScript as a language evolved into something that can be used to build robust applications from frontend to backend, it became increasingly clear that relying on simple implementations leveraging the Event Loop were neither scalable nor robust. Rob Wormald provides a great discussion of some of the methods we have used in the past to handle asynchronicity. I’ve included below some simple examples of how to query the Github public API in various ways, to demonstrate the difference between these approaches.

Callbacks

The use of callbacks certainly offer asynchronicity, but they are less scalable as they often become overly nested, potentially creating the famous Callback “pyramid of doom”. The best example I’ve found of nested callbacks is here – it’s quite amazing! Take a look at this callback example by Rob Wormald:

getStuff(function(result){
  getMoreStuff(function(results){
    getSomeStuffForEachResult(results, function(moreStuff){
       doTheThingWeWantedToDo(moreStuff);
    });
  });
});

So what’s the problem? Well, this turns into spaghetti code really, really quickly, and doesn’t handle errors…really at all.

XMLHttpRequest

XMLHttpRequest, available since the days of IE5, offers a minimal API and the familiarity of checking for requests and response; it is often used in Ajax programming. Cross-domain requests need to be carefully handled when using this protocol. Run this code in this jsbin:

JS Bin on jsbin.com

So, what’s the problem? Try swapping the open Github API call to a different API, say the ColourLovers API (note that you have to ensure that CORS -the ability to post to an external domain – is enabled). This call will fail in the jsbin.

Fetch

The Fetch API provides a more powerful feature set than XMLHttpRequest, leveraging promises to ensure asynchronicity. Run the code in this jsbin.

JS Bin on jsbin.com

So, what’s the problem here? It does seem more readable than the XMLHttpRequest syntax. Well, because it uses promises (see all those .then() calls?), it does not handle rejection well – it will reject a promise only if there is network error such as a CORS issue.

What about Promises?

Promises are often cited as the best way to handle asynchronicity, and have their own built-in object methods. As we saw above, they are used in the Fetch API. You can test how a Promise works here. Promises have various helper libraries such as q.js, When.js, and RSVP.js.

The problem with Promises is that they are neither cancellable nor are they a good way to manage collections of data, although Nolan Lawson explains how to use them most effectively here.

Each of these examples uses the Event Loop in a different way with the same result: functions are processed in their own time, asynchronously. It seems clear that a modern framework that needs to provide some very solid way to handle asynchronous data streams would jump on board one or more of these methods. Or, such a framework might embrace the necessity to become truly reactive: Enter RxJS.

RxJS. It’s not just about feeling better

AngularJS is, as Victor Savkin stated, a “Reactive Framework”:

An Angular 2 application is a reactive system, with change detection being the core of it.

As a framework with reactivity at its core, Angular leverages one of the fullest-features Reactive libraries: RxJS.js, right out of the box. So, what does RxJS bring to the mix? As the RxJS book states,

One question you may ask yourself, is why RxJS? What about Promises? Promises are good for solving asynchronous operations such as querying a service with an XMLHttpRequest, where the expected behavior is one value and then completion. The Reactive Extensions for JavaScript unifies both the world of Promises, callbacks as well as evented data such as DOM Input, Web Workers, Web Sockets. Once we have unified these concepts, this enables rich composition.

RxJS is an incredibly sophisticated library initially built by Microsoft, then revised by the good folks at Netflix including Ben Lesh, and maintained by many open source contributors. It includes, of course, the use of observables, to handle data that is streamed into collections, for use by your app. RxJS offers a clean way to leverage the power of observables to work with complex data, to be cancellable and to clean up after themselves.

Note: One tricky piece of all this new shiny asynchronous magic is that often browsers, which rely on modern JavaScript Engines, sometimes lag behind in their support of these APIs. It’s always worth making your first stop caniuse.com, to ensure that the browser you’re targeting will support your chosen method of handling asynchronicity. Promises, for example, seem to be better supported than Fetch, but if you are forced to support IE11, XMLHttpRequest, which has been around longer, may have to be your choice.

You can use the RxJS API yourself to manage your data streams, or take a look at how Angular itself uses it in the Http module to poll a collection of stocks:

let ticks$ = Observable.interval(5000);
  
let responses$ = 
  ticks$
    .flatMapLatest(() => http.get('stocks.json'))
    .map(res => res.json());
    
let stockPoller = responses$.subscribe(res => console.log(res));
    
//later
stockPoller.unsubscribe();

Note: the use of the dollar sign to designate the observable: ticks$ for example. This naming convention is a matter of personal preferences.

To properly manage data streams in your app, you’re going to want to use observables. And to properly use 0bservables in your Angular-powered app, you’re going to want to study the RxJS API.

RxJs in a NativeScript app

I’ve created a small app that queries the same dataset on Github (my recent Github commits), putting them in a ListView. It’s not beautiful, but it shows how to use observables to grab a list of data and display it (in this case, it’s just the ids of the commits – you could dig into the data in a master/detail format if you wanted to)

First, I create a service that imports the observable from the RxJS library, as well as the ‘map’ function. Note, I don’t import the entire library, just what I need!

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
    
@Injectable()
export class ActivityService {
    
    constructor(
        private http: Http
    ) {}
    
    public getActivities(): Observable<any> {
        return this.http.get('https://api.github.com/users/jlooper/events')
            .map(res => res.json())
    }
}

The service gets the data, maps it to json format, and returns it as an observable.

Then, in the component, I assign a reference to the observable that the service returns:

import { Component, OnInit } from "@angular/core";
import { ActivityService } from "./app.service";
import { Observable } from 'rxjs/Observable';
    
@Component({
    selector: "my-app",
    templateUrl: "app.component.html"
})
export class AppComponent implements OnInit {
    
    public activities$: Observable<any>;
    
    constructor(private activityService: ActivityService) { }
    
    ngOnInit() {
        this.activities$ = this.activityService.getActivities();
    }
}

Here, I’ve called the getActivities function in the service and referenced the Observable in our component. The Observable itself is delineated as activities$ and it will be put into action in our view template.

Finally, I can simply display the parts of the data that I need to, in the ListView bound to the Observable. We use the Angular async pipe to ensure the data is up-to-date. Async pipes also prevent memory leaks because they ensure that, once subscribed to an Observable, the component unsubscribes from them automatically.

 <ListView [items]="activities$ | async">
      <template let-item="item">                  
          <GridLayout>
              <Label class="m-5" col="1" [text]='item.id'></Label>
          </GridLayout>                 
      </template>
</ListView>

Note: it’s a good thing to clean up your subs – if you manually subscribe to an observable, you need to dispose of them by unsubscribing to them manually, so as to avoid any memory leaks.


One way of disposing of Observables

Ugh, so what?

So what, you say, I can still use promises or Fetch or something to make my data sync. Well, I still encourage you to try observables if you are planning to make a scalable mobile app that may start to have to deal with complex data structures, external asynchronous APIs, and other thorny remote APIs. At any rate, it’s the Angular Way and you know you want to ride that train.

What’s next?

It’s extremely interesting to note that, in the spec for EcmaScript 7, a draft to include support for observables out of the box is currently in process of being composed. EcmaScript 2016 already implemented async functions, and they are currently available in TypeScript, which compiles down to ES5, as explained here – so you can use these functions right now in NativeScript if you choose not to implement the Angular way of handling asynchronicity.

The good news is that you have the ability to leverage the power of observables in your web and mobile apps in a robust fashion, as long as you understand the APIs available to use them and their level of browser support.

How are you using observables? Let me know in the comments.

Thank you to technical editors TJ Van Toll, Josh Sommer, Nathan Walker, and Ben Lesh!

Comments