The async/await syntax in ECMAScript 2017 – the next iteration of JavaScript makes coordination between asynchronous promises easier and less painful.
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.
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 a 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 a 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 a promise base on promises by calling Promise.all()
. It’s all right at best.
The process of combining promises is quite complex under the hood.
Have a project in mind?
Let’s meet - book a free consultation and we’ll get back to you within 24 hrs.
With ES7 async
/await
syntax 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 encapsulated in Promise
and run asynchronously. Therefore, it can allow them to wait for other Promise
objects to resolve. 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 a 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, a new version of the method is shorter and safer. The real magic is of course under the hood.
The async
/await
method under the hood.
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!
Have a project in mind?
Let’s meet - book a free consultation and we’ll get back to you within 24 hrs.
Dominik is the Chief Innovation Officer at Gorrion and a full-stack software developer by both heart and trade. He is passionate about new technologies, teaching, and open-source. Sharing knowledge is what truly drives him, so you’ll often find him speaking at conferences and meet-ups. After work, he tends to work even more, but he also likes boxing, cycling, and bartending.