A quick look at async/await

If you’re working with JavaScript, you have to deal with asynchronous operations. Long time ago we did this by using callback functions. Nowadays we’re using promises to make our code more readable. Additionally we get a pretty good tool to handle asynchronous program flow with promises. If your application is a bit more complex and there are multiple asynchronous workflows in your application, your code is likely to get messy over time. You will implement multiple callback functions to handle success and error cases and stack them all together to build your application. To make your life easier ECMAScript defines a new feature called async functions.

A brief introduction to promises

Before we start with async functions in JavaScript we have to take a short look on another technology that’s the foundation of async functions: promises. That’s because async functions just add a convenient interface to deal with promises. So, whenever you make a server call in your browser or read a file in Node.js, you should use promises. In order to demonstrate you the usage of promises, we create a simple function, that resolves or rejects a promise after a given time span with a given value.

function delayReturn (delay, value, success = true) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (success) {
        resolve(value);
      } else {
        reject(value);
      }
    }, delay);
  });
}

To resolve a promise after one second with the delayReturn function and print the result to the console, you have to use the following code block.

function doSomething() {
  delayReturn(1000, ‘Hello World').then(value => console.log(value));
}

But what if the promise is rejected? You have to add another callback function that handles the rejection.

function doSomething() {
  delayReturn(1000, 'Hello World', false).then(
    value => console.log('success: ', value),
    value => console.log('error: ', value)
  );
}

With async functions your code gets cleaned up and you can omit some of the callback functions. But first of all, let’s see what’s behind this brand new feature.

Async functions

Async functions is a new feature in ECMAScript. So the first question should be: Is it already possible to use it? The answer is simple: Yes, but… If you’re using only Chrome later than version 55 or Node.js with the —harmony flag, you’ve got no problem. Other browsers like Firefox, Safari or Edge are currently implementing this feature. To support all the browsers you have to use a polyfill. For Babeljs you have to install the babel-plugin-syntax-async-functions plugin to recognize the new syntax elements and the transform-regenerator, transform-async-to-generator, or transform-async-to-module-method to transform the code for your browser. After you’ve got your setup done, you can use it.

Simply put async functions consist of two keywords: async and await. So you don’t have to learn that much new stuff. To start simple, we rewrite our previous example which printed us the string “Hello World” after one second.

async function doSomething() {
  try {
    const value = await delayReturn(1000, 'Hello World');
    console.log(value);
  } catch (e) {
    console.log('error: ', e);
  }
}

With ECMAScript async functions you can wait for a promise to be resolved or rejected and you don’t have to write one single callback for this. You also can use try-catch to deal with rejections as exceptions. As you can see, your code gets much more readable as with plain promises. And we’re talking here about a very simple example.

Be careful with await

As you know, with the await keyword you can wait for a promise to settle. That means your code is put to a halt until the promise is resolved. Usually this is not a problem. But as soon as you have multiple promises this means they are sequentially executed. If you put two calls to delayReturn in your function, you have to wait two seconds until you see the output.

async function doSomething() {
  try {
    const hello = await delayReturn(1000, 'Hello');
    const world = await delayReturn(1000, ' World');
    console.log(hello);
    console.log(world);
  } catch (e) {
    console.log('error: ', e);
  }
}

To solve this problem, you can use the all method of JavaScript promises. With this method, you create another promise that settles after all included promises (hello and world) are settled. As a result you don’t have to wait two but only one second for the result.

async function doSomething() {
  try {
    const hello = delayReturn(2000, 'Hello');
    const world = delayReturn(2000, 'World');
    console.log((await Promise.all([hello, world])).join(' '));
  } catch (e) {
    console.log('error: ', e);
  }
}

Other ways to use async

The use of the async keyword is not only limited to regular functions. You can also use it with arrow functions or methods. You can easily move your doSomething function into a class, prepend the async keyword to the method’s name and everything works.

class AsyncClass {
  async doSomething() {
    ...
  }
}

const asyncObj = new AsyncClass();
asyncObj.doSomething();

Async/await is no black magic but only a very handy extension of existing concepts to deal with asynchronous JavaScript. All you have to do is getting used to it and use it in your application. It will make your source code a lot more readable and will save you a lot of callbacks.

One Reply to “A quick look at async/await”

Leave a Reply

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