A Primer on ES2017 Async and Await

Follow us on LinkedIn for our latest data and tips!

, , ,

A Primer on ES2017 Async and Await

As the year 2016 draws to a close, attention is now turning to what will emerge from 2017, with Javascript as much as anything. The language is undergoing a massive evolution now, increasingly taking on characteristics that make it attractive as a full stack environment.

The ES2017 (ES8) stack is already now being implemented in both Node and several modern browsers, addressing many of the more complex issues of web development including better ways of dealing with asynchronous coding. This piece will give a short primer on working with the new ES2017 features Async and Await.

Async and Await

More than almost any other language, JavaScript has struggled with a seemingly simple problem – how do you keep interfaces responsive when you have to fetch (or send) contents over a data socket across the web? The first solution to that was to write polling routines to activate a setTimeout or setInterval call, then returning a flag state that indicated a given transfer was complete. With the advent of AJAX calls in the late 1990s, this functionality was relegated to a specific object, the XmlHttpRequest object, and later eventually subsumed in jQuery oriented ajax(), get() and post() functions.

This, in turn, introduced the notion of asynchronous callbacks into Javascript – passing a function as an argument to another asynchronous function with a predetermined set of parameters. Such callback functions would then be invoked once either the data had completed transferring or an error had occurred (in which cases a different function would be passed for cleaning up the action).

One problem became quickly evident with this approach. The resulting callback functions themselves often needed to push the resuting data to another function, which would require another callback, and eventually the resulting code became hideously deep and complex.

The first solution to this problem was to implement a construct called a promise. A promise was a deferred callback object that was implemented initially in ES2015, then refined in ES2016. A promise was a wrapper object that held the callback function(s). When the invoked asynchronous function completed, then it would return a resulting object that could then be passed into a new promise, resulting in a promise chain.

This construct was better, but could still end up being too verbose, especially when what you needed was data from multiple sources independently. The async identifier, along with the await keyword, is the ES2017 solution to that particular problem. As a simple example , first create a promise, in this case a promise of a function that returns a value after a specified number of seconds:

function resolveAfterInterval(x,t) {
 return new Promise(resolve => {
  setTimeout(() => {
   resolve(x * x);
  }, t * 1000);

Here, the function resolveAfter interval takes two parameters, a value that will be squared, and the time in seconds. The function creates a new promise around a function (internally called resolve()) that in turn calls a setTimeout function. The resolve function is itself just a placeholder that returns whatever is passed into it, here the square of the number. The t parameter in turn is used to set the number of seconds before the function returns.

The await keyword is applied to a function or variable to indicate that it should await the completion of the promise before passing the results of that promise. If the await is passed on the variables, then the return statement is invoked once the last of the variables are known, here at three seconds.

async function distance1(x) {
 var a = resolveAfterInterval(20,2);
 var b = resolveAfterInterval(30,3);
 return Math.sqrt(Math.pow(x,2) + Math.pow(await a,2) + Math.pow(await b,2));

Note that that await serves very much the same purpose in an asynchronous function that yield does for a generator (and they use many of the same mechanics under the hood). Here, the output will return only once the longest promise’s interval completes, at 3 seconds.

This is a little different from the situation where the awaits is applied to the functions themselves:

async function distance2(x) {
 var a = await resolveAfterInterval(20,2);
 var b = await resolveAfterInterval(30,3);
 return Math.sqrt(Math.pow(x,2) + Math.pow(a,2) + Math.pow(b,2));

In this example, the first await won’t return until after two seconds, while the second await won’t return until three seconds after the first one is satisfied (or five seconds after the code starts). This occurs because the await acts like an asynchronous block – in the second example, the following statement won’t occur until after the initial function’s promise is returned, but in the first example, the return statement executes once the variables have been assigned.

Using await is actually quite valuable in situations where you want an action to occur once all of the data is available from all sources, but not a moment after. Ordinary chaining of promises is almost as bad as synchronous processing (since you’re dependent upon waiting for one promise to complete before a second one can start, as the second example shows), but with the async and awaits keywords you can reduce this wait only to that of the longest single process.


ES 2017 is the culmination of an upgrade cycle that has significantly changed the flavor of the Javascript language, bringing it more in line with contemporary functional languages such as Haskell or Scala. The language that has emerged is becoming quite powerful and expressive. At the same time, there is a huge amount of innovation occurring with various libraries such as mobX, React and elsewhere, and these in turn are becoming grist for strengthening the core language to better reflect these innovations.