ES2017 Asynchronous Functions (`async`/`await`) The Right Way

Hoang Dinh
5 min readMay 5, 2023
Photo by Javier Allegue Barros on Unsplash

The introduction of Promises and async functions have significantly transformed the landscape of asynchronous JavaScript. The era of error-first callbacks, commonly referred to as “legacy APIs,” is now a thing of the past.

To put it simply, async functions can be seen as a convenient layer built on top of Promises. Their purpose is to provide a more intuitive syntax that mimics synchronous execution, making it easier to work with promise chains. Nevertheless, similar to Promises, the benefits of using async functions come at a cost. The presence of the async keyword necessitates the creation of multiple underlying Promises, which are crucial to enable the use of the await keyword within the function body.

In this story, we will discussion of best practices to async functions.

Convert callback-based to promise-bases

I saw many questions on Stackoverflow which have the same issue — await on a non-promise function.

const result = await getApiResult('url', (error, response) => {
console.log(response) // json object
// Check error, transform...
console.log(result); // undefined :(

Yes, may you know — async/await just a “sugar syntax” to handle Promises. I always repeat 2 things when working with async/await:

  • await just “waits” for a function that returns a Promise
  • async function always returns a Promise

So, what should we do when we have to work with legacy code and libraries which already been implemented by callback-based? — Just convert them to Promise-based by a wapper.

For the above example, we can create a wrapper function like this:

// get all pramaters of legacy function except `callback`
const getApiResultPromise = (url: string): Promise<Result> => { // return a promise
return new Promise<Result>((resolve, reject) => { // resolve first always
getApiResult('url', (error, response) => {
if (error) { // remember to handle the error
return reject(error); // reject and finish
resolve(response); // resolve the response and finish

const result = await getApiResultPromise('url')…