How does async/await simplify JavaScript programming?

The async/await syntax in ECMAScript 2017 – the next iteration of JavaScript makes coordination between multiple asynchronous promises easier and less painful. Especially when you do it right. If in any case you need to fetch data from multiple sources in a certain order, you will end with source code spaghetti – promises and callbacks

The async/await syntax in ECMAScript 2017 – the next iteration of JavaScript makes coordination between multiple asynchronous promises easier and less painful. Especially when you do it right. If in any case you need to fetch data from multiple sources in a certain order, you will end with source code spaghetti – promises and callbacks flavoured.
Today I would like to show some advantages of async/await syntax in ES7.

The promised land!

In ES6 we were all blessed with Promise – JavaScript representation of abstraction of non-blocking asynchronous execution, similar to C# Task or Java Future. In C# Task was introduced in the .NET Framework 4. It is well-known construct to implement TAP (Task-based Asynchronous Pattern) resulting in executing actions asynchronously on a thread pool thread rather than synchronously on main application thread.
Promises are often used for some network input/output operations, e.g. HTTP requests. Creating a Promise doesn’t affect currently executed code and using then method we can easily attach a callback, which will be triggered as soon as the Promise completes. Hey, there’s more! Callback method can return another Promise, so we can effectively chain them.
Let’s say we will use a request library to make our requests.

import request from 'request';
get = url => {
  return new Promise(function (resolve, reject) {
    request({
      method: 'GET',
      url: url,
    }, (err, resp, body) => {
      if (err) {
        reject(err)
      }
      else {
        resolve(body)
      }
    })
  })
}

In code above we create get function that will return a Promise. We can use it to make promise-based request to our imaginary API.

const promise = get('https://imaginary-api.gorrion.io/')
promise.then(response => console.log(response))

Let’s move a little bit further and make three requests, but console.log only concatenation of their responses.

concatPromises = (urls) => {
  let promises = []
  urls.forEach(url => {
    promises.push(get(url))
  })
  return Promise.all(promises)
}
const urls = ['https://imaginary-api.gorrion.io/1', 'https://imaginary-api.gorrion.io/2', 'https://imaginary-api.gorrion.io/3']
const promise = concatPromises(urls)
promise.then(response => console.log(...response))

As you can see, we create promise base on promises by calling Promise.all(). It’s all right at best.

Combining promises


The process of combining promises is quite complex under the hood.

Let it await. For async.

With ES7 async/await sytax we can make our code better. Not only look better, but also work better.
But first things first. How actually async/await in ES7 works?
Every async method in JavaScript returns a Promise. The difference lays in the interpreter. That beast knows that all operations in async functions will be ecapsulated in Promise and run asynchronously. Therefore, it can allow them to wait for other Promise objects to reslove. Entering the await keyword, that can only be used in async methods, allows our code to synchronously wait on a Promise. Using Promise outside of async functions results in need to use then() callback.
Here I will present two functions that are equivalent, but one of them will be async.

nonAsnycFcn = () => {
  return Promise.resolve('Hey, I am the result!')
}

And:

asyncFcn = async () => {
  return 'Hey I am the result!'
}

Both will return the same result.
Knowing all that, we can tweak our concatPromises() function and use async/await.

const asyncConcatPromises = async (urls) => {
  let results = [];
  for (const url of urls) {
    results.push(await get(url));
  }
}
const urls = ['https://imaginary-api.gorrion.io/1', 'https://imaginary-api.gorrion.io/2', 'https://imaginary-api.gorrion.io/3']
const results = await asyncConcatPromises(urls)
console.log(...results)

As you can see, using await allowed us not only to remove Promise.all() function, but also made our method return array of whatever we get from API instead of single Promise, for which we need then() callback. Thus, new version of method is shorter and safer. The real magic is of course under the hood.

Async results


The async/await method under the hood.

Conclusion

The async/await keywords are dependent on each other, so you can’t use await outside the async function. But you can call your async function as below.

const urls = ['https://imaginary-api.gorrion.io/1', 'https://imaginary-api.gorrion.io/2', 'https://imaginary-api.gorrion.io/3']
asyncConcatPromises(urls).then(results => {
  console.log(...results)
})

Seems familiar? Yes, we have just used async method as if it returned Promise.
In fact async/await are syntactic sugars, which are translated into Promise and then() callback. Every Promise can be rewritten using async/await and vice versa. Ultimately, using one method or another is a matter of style and brevity.
Finally, I can only recommend giving async/await a try!