JavaScript Async Await: Promisify the future to callback never again!
By: Arnold Abraham
Tags: JavaScript, Web Development, Technology, Self Improvement, Programming

JavaScript Async Await: Promisify the future to callback never again!

Callbacks to Promises up to Async Await

Intro

Having a C# background? Then you are familiar with async-await. JavaScript introduced these keywords in 2017 into the language. They help to get rid of problems you had back then whenever it came to asynchronous code.

Asynchronous code, known for using callbacks so far, that are mostly nested and lead to hardly comprehensible code. Here is a picture of a callback hell or also known as the pyramid of doom [2], [1].

author: summary so far (All rights reserved)

There are plenty of options to solve this problem, but none of them came out big and became the method to go along. All of them bring their own problems to the table. Be it promises or generator functions or even modules like Async.JS [3].

Yesterday’s code

Although async and await is a significant change, we should not throw away old concepts. Async await is based internally on generator functions and promises. And on what do promises rely on? Right! Callbacks. New abstraction levels bring better ways to encapsulate old concepts but also keep the same problems. Joel on Software did a great job about that circumstance [4].

Concrete speaking: Async-Await is only usable with functions that already rely on promises. If you have methods that aren’t, you have to convert them in order to use async-await. A good way to do so is to use a technique so-called wrapping. Wrap your existent callback-based function into another function that uses a promise. Here is an example of the usage of a readFile to show you what I mean.

The wrapper function is clearly visible, calling the promise constructor. The body exposes the origin function, based on the callback mechanism.

Now imagine you are doing this the whole day and for different projects. This is a hideous task and will bring you only pain and suffering. Fortunately, there is hope. If you are working in a Node.JS based environment, you can fasten this up. There is a guideline where the callback is the last parameter of a function. Returning an error is mostly the first parameter of this function. When your code aligns with those guidelines, you can just use the utility-function of Node.JS promisify [5].

We can profit massively from the spread operator here.

This snippet is pretty confusing. Take your time and inspect this abstract diagram with the execution order of the lines and the explanations right beside:

“Promisify the future”-explained, Author: Arnold Abraham

Nowadays

With version 8.0 Node.JS introduced a built-in utility [5] for you to use the promisify easier and make it able to use the async-await keywords. You can get rich source code easy to comprehend and very compact.

Look at this code, does it read like a synchronous one? Yes, definitively, but it is not going to be executed synchronously. The function after the await is getting split up into a co-routine. Technically a generator function and while waiting, asynchronous code can continue to run.

In order to use await, the function itself has to be marked with the keyword async. Calling the function processFile can be also awaited as long as the caller method is also an async marked one. The caller can also be awaited as long as the caller of the caller is an async method.

Remembering the part where I mentioned the pyramid of doom. Can be constructed here as well. New technics, old problems. Furthermore, even nested if statements can be constructed as a pyramid of doom.

First Order Await?

The pyramid of doom problem brings up some questions. What has to be the first order of this chain? Shouldn’t then be the main function of a program or for JavaScript the entry function to be asynchronous as well? Technically yes, but it is synchronous. What to do also?

First aid could be a self calling async function:

Only to mention, in this StackOverflow-answer are listed separate ways to invoke an async inside your entry point. [6]

Async is also usable with lambdas and of course as you saw in the example with try-catch (03_AsyncAwait.js). This is not possible with pure promises or callbacks. A try-catch would syntactically break the synchronous program execution.

Because of the look-alike to a synchronous one, the control structures for synchronous programming can be included easily. Especially for loops, async-await turned out to be very useful. It lets the reader of your code comprehend the loop without an asynchronous mindset, although it is.

Did you ever try to make a loop with a pure callback or promise-based code? Then you know what I am talking about.

Conclusion

When you want to insult, dig deeper and you will find something. Here you could argue async-await does not solve fundamental problems of development. JavaScript does not get more skills, it had before and lastly, also no new technical problems are solved with those two keywords. And you are right, but for readability and the time, that is consumed by understanding and also by writing code, there is an enormous difference made up by async-await.

Addressing easier life while coding, faster comprehensibility, and maintainability, less error-prone are things, where I would say, async-await has made its position more than just clear and brings JavaScript a lot.