fbpx Skip to content

Aquent | DEV6

TypeScript – Async and Await

Written by: Hasan Ahmad

User interfaces are inherently asynchronous, but one of the biggest challenges of writing JavaScript based front-end web applications is managing the complexity of your asynchronous code.  As your application becomes more mature, requirements start to become more refined, and edge cases begin to emerge. You begin to realize that certain parts of your code should only execute when particular conditions or events are met, requiring the use of callbacks and event handler functions, to avoid holding up the rest of your application execution.

To improve this, TypeScript introduced a new feature. Using two new keywords async and await – you can now write asynchronous code in a way that resembles synchronous code.

typescript

Instead of having to move logic inside of chains of callbacks (perhaps from a chain of promise resolutions), we can now modify calls to functions that return promises with await, inside of functions that have the async modifier. await can only be used inside of functions that are modified with async, and implicity, their return values are wrapped in Promise.resolve, so they too return promises. You can only await function calls that return promises.

For example:

/* function that returns a ES6 Promise, randomly resolves or rejects to trigger error handling */

function getUserNameAsynchonously(): Promise<string> {

      var promise = new Promise((resolve, reject) => {

            if (Math.round(Math.random() * 10) % 2 === 0) {

                  window.setTimeout(() => {

                        resolve('Tom Joad')

                  }, 1000);

            } else {

                  window.setTimeout(() => {

                        reject();

                  }, 1000);

            }

      });

      return promise;

}

 

console.log('Loading User:');

/* The old way of asynchronous promise resolution */

getUserNameAsynchonously().then((username: string) => {

      console.log(username);

}).catch(() => {

      console.log('Failed to load user.');

});

/* The new way with async/await */

async function callAsync() {

      try {

            var username: string = await getUserNameAsynchonously();

            console.log(username);

      } catch (error) {

            console.log('Failed to load user.');

      }

}

callAsync();

This new feature allows us to write asynchronous exception handling code similar to synchronous exception handling, with try/catch. I feel that this improves the readability of complex asynchronous logic significantly.

To see this working on an actual web page, check out our repo on Github for a Typescript powered web-page, using the async/await feature. Because we target ES5 in this example, were going to use es6-shim for its ES6 Promise implementation.

The best part: Async/await has actually been a feature of TypeScript since version 1.7, but only available if you were targeting ES6 (the feature was originally implemented with ES6 Generators and Promises). With TypeScript 2.1 (released in December 2016), we can now use async/await in projects targeting ES3/ES5, as long as you have a polyfill for ES6 Promises in your project. This means if your project supports browsers that don’t have complete ES6 support, this is now available to you.