A high way to Observables


If the title of this post reminds you of an ACDC song then you are my type of audience! There is a long way to Observables. What are these? How did we reach them and why? Which were the previous stops of this highway, the highway of asynchronicity on the web? By reaching the end of this post you will be able to understand what problems do Observables solve, you will briefly review previous techniques which are solving the same issue and then we will dig into the anatomy of an Observable and understand its competitive advantage over its predecessors.

Asynchronicity on the Web

Code in programming is mostly executed sequentially and straight away, with one thing happening at once. Sometimes the results of one function are needed in another function. That means that the latter function cannot be executed unless the former has finished. Such dependency between operations is seen often in events. In programming languages such as Java or C#, as it is also mentioned in this article, the “main program flow” happens on the main thread and the “occurrence of events” independently of the main flow.

This is not the case with Javascript. In Web development such dependency between tasks can have serious side effects on UI. Browser will stop responding, will loose control and will be shown as frozen until the current task will be finished. For example if you click on a button which is supposed to do some expensive calculations (like drawing million of dots on a canvas) and then you try to click on another button of the same page you might see that the second button is not clickable and the browser seems to be inactive. In this article the aforementioned phenomenon is described as blocking. Blocking happens because Javascript is a single threaded language, meaning that a program can use a single process to complete tasks. Tools such as web workers are helpful in the sense that they enable the run of a separate script on the background, allowing the main thread (UI) to run without being blocked. However they still do have their limitations because mostly they cannot access the DOM and some global javascript objects. To fix such problems, browsers allow us to run certain operations asynchronously.

So asynchronicity or asynchrony refers to the occurrence of events independent of the main workflow. If we may elaborate on this we could say that characteristic of these events is that the duration of their execution is not known. For instance accessing or fetching some kind of resource from an external device, such as fetching a file from the network, accessing a database and returning data from it (via mostly an Ajax request) or accessing a video stream from a webcam are examples of operations that can run in an asynchronous way. That means they can run on the background, off Javascript’s execution, allowing other operations to run in main flow without causing any blocking in the browser.

Asynchronous Events Techniques

There are different techniques of handling asynchronous events. Being myself a frontend engineer over the past couple of years I have seen the whole path and evolution of various asynchronous techniques, starting from the old school Callbacks and the widely used Events API (which is a specific type of callback), proceeding to Promises and later their enhancement with the Async/Await until reaching to Observables. Thorough explanation of the aforementioned techniques has been extensively done in many other articles and tutorials across the web. Below follows a brief description for each one of them, pointing out their core syntax & usage along with their weakness and the reason to move on to the next technique. Some brief explanation about the code that is being demonstrated in the next paragraphs: For each one of the techniques below i have created example code. Access to the full code you can have on the referenced jsfiddles links. For every example i am out putting the results both in the console and in the browser in the jsfiddle. For the latter the helper function createElement has been used in order to write on the DOM and demonstrate on jsfiddle’s browser the output result.

Callbacks

Callbacks are functions that are passed as arguments to other functions which are being executed at that moment. Once the “host” function has finished then callbacks are being executed. Asynchronous operations are being handled in this way without any side effects of blocking. However this solution is not optimal. Imagine what will happen if in turn another function depends on the results of the callback function? In such a case we would need to pass the last function as argument to the second function. A nest of callbacks will be then created forming the widely-known callback hell. In the figure 1 below you can see my own example of callback hell.

Callback Hell without Error Handling
Figure - 1: Callback Hell without Error Handling

Above is depicted the execution of callback functions within “host functions”. So “host functions” should firstly be declared in a way to accept functions as an argument. Their declaration looks like in Figure 2. You can run and see the full code (declarations & executions) in this fiddle.

Figure -2 : Declaration of Host Functions for Callbacks

Promises

Promises is a newer technique that somehow improves the callback hell by providing syntactic sugar on it. A promise, as is described here, is an object that may produce a single value some time in the future: either a resolved value, or a reason that it’s not resolved (e.g., a network error occurred). In other words it wraps asynchronous operation and notifies when it’s done. The method .then() is used when a result is successful and the .catch() when not. The power of promises over callbacks is that when we have several asynchronous operations and one depends on the other we can chain them with sequential .then(). So nested callbacks are equivalent to chaining in promises. This is easier to read, to test, to maintain and resembles synchronous code. Be careful, the concepts of callbacks and promises are not interchangeable. The latter is an object that represents a result after the execution of a callback. In Figure 3 below you can see the previous example written in the “Promises” way. You will notice that nested code has been replaced by chain-able code.

Figure — 3 : Promises Hell without Error Handling

In the code above you can see the execution of promises. Their declaration looks like in Figure 4. The full code (declaration & execution) is available in this fiddle.

Figure — 4: Promises Declaration

Async/await

Async/await is getting even closer to the coding style of synchronous programming and is built on top of promises and it is one more layer of syntactic sugar. It is still non blocking code. The async keyword when placed in front of a function declaration transforms it into asynchronous code. Asynchronous functions can be paused if we use the await keyword within them and thus code is much easier to understand. The await functions is exactly the same way as .then() on standard promises. It will pause the execution until the value of the promise is available. More extensive tutorial about async/await you can find in this site. In Figure 5 below you can see the previous examples written in the “async-await” way. Comparable to the standard promises approach what changed is the invocation of the code. The declarations of the functions that return a promises remained the same and their execution changed including the async and await keywords. Access to the full code can be found in this fiddle.

Figure — 5: Promises with Async-Await, without Error Handling

Observables

Using the definition from this article an Observable is a unique Object similar to a Promise that can help manage async code. In a more technical definition Observables are lazy Push collections of multiple values. Lazy means that observables are declarative and are not executed unless a consumer subscribes to them. A quite comprehensive description of Observables is given in Angular Documentation, where it is stated that they provide support for passing messages between publishers and subscribers in your application. Observables are not part of Javascript yet. However, ReactiveX is an API for asynchronous programming with observable streams which has been implemented in different languages. Rxjs is the javascript implementation of ReactiveX. The latter is a combination of the best ideas from the Observer pattern, the Iterator pattern, and functional programming. Plain Observables are unicast. Subject is a special type of Observable that allows values to be multicasted to many Observers. Another interesting term of Observables are Operators. They are pure functions which when operated on an Observable return another Observable by manipulating its data. On the Figure 6 below you can see how the previous example has been converted into Observables-Way. FlatMap is an operator that is used to chain Observables.

Figure — 6: Observables without Error Handling

In the code above we saw the execution of Observables. Their declaration looks like Figure 7. In a later section we will see different other ways on how to create an Observable. Access to the full code (declaration & executions) you can find in this fiddle. The Async/Await approach is among the cleaner ones in terms of readability. However once of its main drawbacks comparable to Observables is that Promises are executed only once while the observables carry over streams of data and emit multiple values. That means that Pasta in the code above can be poured into bowl for boiling into chunks at repeated intervals in time, like in real life.

Figure — 7: Observable Declaration

In depth Anatomy of Observables

Let’s elaborate a bit on Observable. It is actually an Object whose purpose is to transfer streams of asynchronous data between parts of an application. What is the structure of this object or in other words what values/streams of data does it deliver and emit? How these data streams are created? Where exactly will these data be emitted, how will they be transferred and when?

The “What”

What type of data are emitted via observable? As a general term, we refer to data published by an observable as a stream. A stream is a sequence of objects, but unlike other sequences, it’s handled lazily, so the items aren’t retrieved until they’re required. You can put anything in your stream characters, messages, numbers, http requests, or even user events. So there are different types of streams based on the type of data they are carrying. An extensive guide on how to create streams in RxJs can be found here. Some common use cases where multiple values are needed over time are web sockets with push notifications, user input changes, repeating intervals, cursor movements, inputs from sensors, postMessage communications from Web Workers, iFrames, or windows Storage change events from localStorage or indexedDB. A good dive into streams and how they can simplify web life is described here.

The “How” of “What”

How can we create the “ what” of an Observable or in plain words how can we create an observable? Mostly by using ReactiveX and Rxjs operators and in some cases they are built-in in frameworks such as in Angular. They are also used in React/Redux ( redux-observable).

  • There are ReactiveX operators (and their respective Rxjs operators ) which are used to generate new Observables. For every ReactiveX operator there is implementation for different programming languages. The javascript one is what concerns us. The mostly used ones of them are the following:
  • Observable.create create an Observable from scratch by means of a function. We can actually transform anything asynchronous such as API methods into an Observable if we wrap it within an Object.create(). See this article of mine for more details with examples
  • Observable.interval create an Observable that emits a sequence of integers spaced by a given time interval
  • Observable.from It converts various other objects and data types into Observables. There are utility functions of this category which have been implemented in Rxjs Library. The most common ones, as also described in Angular, are:
    - From A Promise
    - From a Counter
    - From an Event
    - From an Ajax Request
    - FromEventPattern
    - Of: It emits variable amount of values in a sequence and then emits a complete notification.
  • Except from using creation operators to produce observable, they are also built in Angular as Interface. The following Angular features, when used, an Observable is created :
    - Event emitters (keystroke events)
    - An Http Request (http request)
    - Router
    - Forms modules

The “When”

When this emission will happen? This will be done when the asynchronous operation will be ready. If it is a network request whenever the response will be retrieved from the server, if it is a keystroke event from the user whenever he interacts with a button etc.

The “Where”

They will be emitted where they are needed i.e. on a specific part/component of the application such as ie. the header, a media gallery component. So we need explicitly to “wait” and “listen” to the emissions in the respective component in order to “consume” them.

The “How” of “emission”

How these signals (either events or literals or any type of streamed data) will be emitted? Via Observer Objects asynchronously. The Observer Objects communicate with the Observable and are in charge of transferring the emitted value or errors via the subscribe() method. Observer is an object that defines callback methods to handle three types of notifications that an observable can send a) next, b) error and c) complete. These 3 types refer to the 3 different values that are sent after the execution of an Observable. When an Observable sends “next” then one of the “what-values” described above is transmitted, when an “error” is sent then a javascript error is thrown and when “complete” is sent then no value is sent. More than one Observer Objects compose an Observable, meaning that an Observable contains a list of Observer objects, each one in charge of delivering a different value/message. In the diagram 1 below you can see the correlation between the observable, the observer and the value x transmitted via the observer. The latter (x) refers to the “what” type of data an observable stream can deliver. As was described in a previous section anything can be transmitted from a number, string until a user event.

Diagram 1: Observable as a Stream Sequence of Objects

Once the observer object(s) is created it is consumed via the subscribe method (Diagram 2). Alternatively, the subscribe() method can accept callback function definitions in line, for next, error, and complete handlers.

Diagram 2: Consumption of an Observable via subscribe

Asynchronous Techniques Comparison

In this section we visualize in the table below a parallel comparison between the various asynchronous events techniques. All the information presented, analysed and compared below is based on personal knowledge as well as on research on different other web resources. Useful insights about error handling in Promises have been used from this article. In this Angular training material is described the retry capability between Promises and Observables. Quite an interesting comparison between Observables and Promises is done here. The road to Promises and benefits of Promises with Async/Await are explained in this link. An elaborated discussion on the vulnerabilities of error handling and its debugging in Promises is described in this post.

Within the table below you can see the 3 different comparisons, one between callbacks and promises, one between promises and observables and the last one between promises and promises with the async/await.

Out of all asynchronous techniques the most recent ones and widely adopted ones at the time this article is written are the Observables and the Promises with async/await.

Table: Asynchronous Events Techniques Comparison