DEV Community

Cover image for Mordern Javascript: Utilizing The Async-Await Feature.
Walkr's-Hub
Walkr's-Hub

Posted on • Edited on

Mordern Javascript: Utilizing The Async-Await Feature.

Introduction

In modern JavaScript where we have features like Promises and arrow functions etc. None of them are, In my opinion a bigger improvement to the language than Async-Await. Async-Await makes it easy to work with our promise based code that looks more synchronous than asynchronous.

In this article we would be looking at how Async functions work in great detail, It's advantages and practical use cases.

What is Async-Await?

Async Await is merely a small set of tools that makes it easier to work with promises. It allows continuous usage of promise methods, and it helps us to better manage a lot of asynchronous activities while building our applications.

Prerequisites

  • How to use the Command Line/Terminal.

  • Basic Understanding of Javascript Promises.

  • Writing Arrow Functions.

  • Using setTimeout().

  • Node is installed.

Getting Started

We'll start by creating a directory that contains our JavaScript file. You can go to your terminal and type the following:

mkdir async
Enter fullscreen mode Exit fullscreen mode

To change directory into async , type the code below:

cd async
Enter fullscreen mode Exit fullscreen mode

To create a new Javascript file called "async-await.js" with a variable inside it, type the code below:

echo var msg > async-await.js
Enter fullscreen mode Exit fullscreen mode

Now, we can open up our directory in visual studio code via the command below:

code . 
Enter fullscreen mode Exit fullscreen mode

Functions and Async Functions (How they differ)

To really grasp how functions differ from Async Functions, Let us create an arrow function called 'doWork'. This function is going to be empty and we would log it's result to the console using the code below:

let doWork = () => {
};
console.log(doWork())
Enter fullscreen mode Exit fullscreen mode

This would print out on our terminal undefined when we run our async-await.js file, this is because functions usually expect a return value. To run our file, open up your command line and type:

node async-await
Enter fullscreen mode Exit fullscreen mode

Image description
In order to make our function an async function, all we would do is mark the function as async, just before the function declaration. i.e

let doWork = async () => {
};
console.log(doWork())
Enter fullscreen mode Exit fullscreen mode

With this small change to the code we are already changing the behavior of our program. We would no longer see undefined printing to our terminal. To see this, we need to run our file once again by using:

node async-await
Enter fullscreen mode Exit fullscreen mode

Image description
In this case what we get back is a promise that has been fulfilled with the value of undefined.

This is the first thing to note about async-functions, Async functions always return a promise. This promise is fulfilled with the value, you choose to return from the function. Currently we are not returning anything, that's why it is fulfilled with undefined.

Now, let us explicitly return a value from the async function. To do this, let us return a string containing my name.

let doWork = async () => {
   return "Emmanuel"
};
console.log(doWork())
Enter fullscreen mode Exit fullscreen mode

One thing to note though, the return value from doWork() is not "Emmanuel", it is actually still a Promise, that has been fulfilled with the string "Emmanuel". When we run our code, we see what this means

Image description

Using .then() and .catch()

We aren't really doing much by just logging out a return value, let's see how to use the .then() method to run some code when the async function gets fulfilled.

To get this done, we just need to use the .then() method on our doWork function. As an example, we would simply log the result of its embedded arrow function. Which contains the return value of the async function

let doWork = async () => {
   return "Emmanuel"
};

doWork().then((result) => {
   console.log("Result", result)
})
Enter fullscreen mode Exit fullscreen mode

Here's the result for that:

Image description

We can also set up a .catch() call which is simply a function that gets an error. Lets's chain it to our .then() method with the code below:

let doWork = async () => {
   return "Emmanuel"
};

doWork().then((result) => {
   console.log("Result", result)
}).catch((e) => {
  console.log("e", e);
})
Enter fullscreen mode Exit fullscreen mode

Just one small problem, When we run our file, we still get the result to be "Emmanuel".

So, how do we ever get .catch() to run?
Well, if we throw an error from our async function, It's going to be the same as rejecting the promise that gets sent back from the async function.
To throw an error, modify your code with the one below:

let doWork = async () => {
   throw New Error("Something went wrong")
   return "Emmanuel"
};

doWork().then((result) => {
   console.log("Result", result)
}).catch((e) => {
  console.log("e", e);
})
Enter fullscreen mode Exit fullscreen mode

This time around, when we run our code we get our "e" string as well as the entire error object.

Image description

Using the Await operator

So far we have looked at the basic structure of Asynchronous Functions. Now, we would be exploring the other half of the Async-Await feature.
The await operator can only be used in async functions and since the whole point of async await is to make things easier when working with promise based code.

To spice things up, let's create a promise based code, this would just be a promise that adds up two numbers after two seconds, Here's the code for that:

const add = (a, b) => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(a + b)
        }, 2000)
    })
}

let doWork = async () => {
   throw New Error("Something went wrong")
   return "Emmanuel"
};

doWork().then((result) => {
   console.log("Result", result)
}).catch((e) => {
  console.log("e", e);
})

Enter fullscreen mode Exit fullscreen mode

If we were to use promise chaining, the code would require .then() calls and callback functions, just to get the value of add().

With Async-Await, it eliminates this monotonous way of doing things.

What we get access to, inside our async-funtion is the await operator. The await operator works with promises. And since we already have a promise called add, we would use it with the await operator. We are going to add two numbers together and then await the result of the add promise, which we would store inside our variable called "sum" and then return the value of "sum"

const add = (a, b) => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(a + b)
        }, 2000)
    })
}

let doWork = async () => {
   const sum = await add(1, 99);
   return sum
};

doWork().then((result) => {
   console.log("Result", result)
}).catch((e) => {
  console.log("e", e);
})
Enter fullscreen mode Exit fullscreen mode

When we run our async-await.js file again, we get the result below.

Image description

Performing Multiple Tasks with Async-Await

Awesome, we have used await for the first time in our application. We can even take things a step further by performing other promise based tasks in our async function.

I would be making more calls to add() by using the value for the the previous sums. Here's the code for that

const doWork = async () => {
   const sum =  await add(1, 99)
   const sum2 = await add(sum, 50)
   const sum3 = await add(sum2, 3)
   return sum3
}
Enter fullscreen mode Exit fullscreen mode

This is going to make several calls to sum, we would have to wait 2 seconds for every promise to get fulfilled. This tells us that async-await doesn't necessarily make things faster, it just makes things easier to work with. After we wait for 6 seconds, we would get out final result to be 153

Image description

One advantage Async-Await gives us, is the ability to put all of our promise calls in the same scope. This makes for more readable and synchronous looking code.

Now, all that's left is to wrap things up by writing some error handling code when our promises get rejected. We would be adding an if statement that helps us to check if the numbers to be added by sum() are negative numbers. We would return the reject code so that it finishes and then rejects the promise if that condition is met.

Let's improve our add() function by adding the if statement.

const add = (a, b) => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (a < 0 || b < 0) {
                return reject('Numbers must be non-negative')
            }

            resolve(a + b)
        }, 2000)
    })
}
Enter fullscreen mode Exit fullscreen mode

If we run our async-await file after this is added, we would get the same output, But when we make some changes to the numbers in add(), We get our error showing up: Here's the code and image for that below:

const add = (a, b) => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (a < 0 || b < 0) {
                return reject('Numbers must be non-negative')
            }

            resolve(a + b)
        }, 2000)
    })
}

const doWork = async () => {
    const sum = await add(1, -99)
    const sum2 = await add(sum, 50)
    const sum3 = await add(sum2, -3)
    return sum3
}

doWork().then((result) => {
    console.log('result', result)
}).catch((e) => {
    console.log('e', e)
})
Enter fullscreen mode Exit fullscreen mode

The output:

Image description
The output is going to get logged after we wait for the initial 2 seconds which is on our setTimeout() function.

Conclusion

So far, we have looked at how async await differs from functions, the await operator and how to perform multiple tasks with async-await. We also learned that async-await gives us one-scope to put in our promises in.

I hope this article has been of help, Please leave a comment and follow me to get more content.

Top comments (2)

Collapse
 
andrewbaisden profile image
Andrew Baisden

Nice article I use async await all of the time now the syntax is just so clean.

Collapse
 
mr_walkr profile image
Walkr's-Hub

Thanks Andrew, I also use it in my projects as well