How to effectively utilize Promise in JavaScript using Async/Await
Tags: javascript, webdev, beginners, programming
Published: 2022-10-25 19:42:29

JavaScript supports three approaches to handling asynchronous operations.

The first approach involves using callback functions. In this approach, when an asynchronous operation completes, a callback function is invoked that was passed as an argument.

See the code below:

```
function callbackFn(){
  //execute when the async operation completes
}
// pass callbackFn as an argument
asyncOperation(callbackFn)
```
Using this approach results in callback hell, which creates complex, difficult-to-read, and error-prone applications as you nest callbacks into callbacks.

To handle asynchronous operations effectively, JavaScript introduced `promises` to solve the issue with callback hell.

A `Promise` is an object that serves as a placeholder for the future result of an asynchronous operation and represents our operation's current state.

Upon completion of the asynchronous operation, we return a fulfilled promise object. In the promise object, we use the `then()` method to utilize the result.

The syntax is as below:

```
const promise = asyncOperation()
promise.then(result => console.log(result))
```
`Promises` introduce a better improvement in handling asynchronous operations and solved the challenge of callback hell.

The only problem is, Promises require a series of `then()` to consume any returned Promise object, which increases the wordiness of our code.

`async/await` was introduced in ES2017 as a better approach to handling `Promises`

In this post, we will learn how to use `async/await` to utilize `Promise`.

By the end of this article, you will learn:

- Why async/await is referred to as syntactic sugar
- How to declare an async function
- What is the async keyword
- What is the await keyword
- Difference between consuming Promises using .then() vs async/await
- The benefits of using async functions
- How to handle errors in an async function

Let's get started !

## Understanding Syntactic Sugar
`async/await` is referred to as syntactic sugar to Promise, but what does this really mean? Syntactic sugar is syntax within a programming language implemented to make code easier to read or express.

Rather than using Promise Chaining, we can use async/await to write well-structured code

The code below looks well-structured and devoid of wordiness.

```
async function getSomeData(){
  const response = await fetch('https://jsonplaceholder.typicode.com/posts')
  const data = await response.json()
  console.log(data)
}
//call the asynchronous function
getSomeData()
```
## Understanding the Async keyword
The `async` keyword prompts the JavaScript engine that, we are declaring an asynchronous function.

Using the `async` keyword prior to a function automatically transforms it into a `Promise`. Meaning, the return value of the async function will always be a Promise.

If the returned value of any async function is not clearly a promise, it would be silently wrapped in a promise

See the code below :

```
async function someAsyncOps(){
}
//call the asynchronous function
console.log(someAsyncOps())
```
See the code below:

```
async function someAsyncOps(){
}
//call the asynchronous function
console.log(someAsyncOps())
```
The output of the code will be


![AsyncAwait](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6fpe4pwwbht79l1z1hhj.jpg)

- There is no return value in the body of the function above. However, because of the async keyword used, the returned value was a `Promise`

To reiterate, using the `async` keyword prior to any function, the return value is a `Promise`. This promise will be settled with the value returned by the async function or rejected with an exception thrown from the async function

## Syntax of the Async function
We define the async function using either the regular function declaration or an arrow function.

The syntax of the async function is as below:

```
//function declaration 
async function someAsyncOps(){
  await ... //some async operation goes here

}
//arrow declaration
const someAsyncOps = async ()=>{
  await ... //some async operation goes here

}
```
## Understanding the Await keyword
When an `await` expression is used, the execution of an async function is paused until a promise settles (fulfilled or rejected), returns the promised result, and then the execution resumes.

When resumed, the value of the `await` expression is that of the fulfilled promise.

The `await` keyword works only in the body of an async function. It prompts the JavaScript engine to wait for the asynchronous operation to complete before continuing with any statement below it in the function's body.

It works as a **pause-until-done** keyword, causing the JavaScript engine to pause code execution until the Promise is settled.

The syntax is as below:

```
//should be used inside an async function
let value = await promise //wait until promise is settled
```
Examine the code below:

```
async function someAsyncOps(){
  //use Promise constructor
  let promise = new Promise((resolve, reject)=>{
    setTimeout(() => resolve('done'),4000)
  });
  let result = await promise; // (*) wait until promise settles
  console.log(result)

  console.log("Will resume execution when promise settled")
}
someAsyncOps()
```
In the code above:

The function execution "pauses" at the line (*) waiting for the promise to settle. Using the setTimeout to stimulate a delay, the promise takes about 4 seconds to settle. Once the promise settles, we return the fulfilled value to the result variable. After, any statement below that line of code will be executed.

To emphasize, the await hangs the function execution until the promise settles, and then resumes it with the promised result.

It is used as an alternative to promise handling rather than the `.then()` method.

## Inside the Async function's body
An async function's body can be thought of as being divided by zero or more await expressions.

**Top-level code is executed synchronously** and includes the first await expression (if there is one).

This way, an async function without an await expression will run synchronously. The async function will, however, always complete asynchronously if there is an await expression inside the function body

Run the code snippet below to understand

```
async function someAsyncOps(){
 console.log("Top level code will execute first ") //executed synchronously
  //use Promise constructor
  let promise = new Promise((resolve, reject)=>{
    setTimeout(() => resolve('done'),4000)
  });
  let result = await promise; //wait until promise settles, hence run asynchronousy
  console.log(result)

  console.log("Code below will resume execution now that the promise has settled")
}
//invoke the function
someAsyncOps()
```
The output will be

![AsyncAwait](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8wihph6ixbmp1yl040jr.png)

## Benefits of Async/Await
With async function, the JavaScript engine will pause any code execution when it encounters the await expression, and only resumes when the promise is fulfilled.

The code below uses the async function:

```
async function someAsyncOps(){
 console.log('Async/Await Readying...')
 let response =  await fetch('https://dummyjson.com/products/1')
 let result = await response.json() // pause code execution until promise is fufilled
 console.log(result)
 console.log('This will only execute when the promise is fulfilled')
}
someAsyncOps()
```
The output will be:

![AsyncAwait](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8ks48rilbzukte45yogi.png)

However, the `.then()` method does not pause any code execution. Code below the promise chaining will execute before the promise is fulfilled

The code below uses Promise chaining

```
function getData(){
 console.log('Then method reading....')
   fetch('https://dummyjson.com/products/1').then((res)=> console.log(res))
   console.log('This will not pause, but will be executed before the promise is fulfilled');
}
getData()
```
The output will be

![AsyncAwait](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2bsv37btdc4qv35bgty4.png)

If we utilize promise chaining with `then()`, we need to implement any logic you want to **execute after the request in the promise chaining**. Else like the example above, any code that you put after fetch() will execute **immediately**, before the `fetch()` is done.

`Async/Await` also makes it simple to convert code from synchronous procedure to asynchronous procedure.

## Handling errors in an Async function
Error handling in async functions is very effortless. If the promise is rejected, we use the `.catch()` method to handle it.

Because async functions return a promise, we can invoke the function, and append the `.catch()` method to the end.

```
//handling errors in async functions
asyncFunctionCall().catch(err => {
  console.error(err)
});
```
Similarly to synchronous code, if you want to handle the error directly inside the async function, we can use `try/catch`.

The `try...catch` statement is composed of a `try` block and either a `catch` block, a `finally` block, or both. `try` block code is executed first, and if it throws an exception, `catch` block code is executed.

See the code below:

```
async function someAsyncOps(){
 try {
   let response =  await fetch('https://jsonplaceholder.typicode.co') //api endpoint error
 let result = await response.json()
 console.log(result)

 } catch (error) {
 console.log("We got some error",error) //catches the error here
 }
}
someAsyncOps()
```
The output of the code will be:

![tryCatch](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4h9xsquiopnctzv5fgir.png)

## Summary
- Using `async` keyword prior to a function automatically transforms it into a `Promise`.
- When an `await` expression is used, the execution of an async function is paused until a promise settles (fulfilled or rejected), returns its result, and then the execution resumes.

- Because the `await` is valid only inside async functions, the await expression does not block the main thread from executing.
- With `async/await` we rarely need to write `promise.then/catch`
-These features make writing both readable and writable asynchronous code a breeze.

Please do comment or add your feedback, insight, or suggestion to this post. It helps clarify any concerns you might have and makes the article better.

If you have found value in this article, kindly share it on your social media platforms, and don't forget to connect with me on [Twitter](https://twitter.com/emmanuelfkumah)