A taste of syntactic sugar with async/await
Tags: javascript, beginners, webdev, programming
Published: 2021-03-01 23:24:28

## What is syntactic sugar?

In computer science, a syntax or feature designed to make a piece of code easier to express or to read within a programming language is referred to as **syntactic sugar**.

> *It makes the language "sweeter" for human use: things can be expressed more clearly, more concisely, or in an alternative style that some may prefer.*


## Basics of Async/Await

The `Async function` and the `await` keyword were introduced with the ES8 (2017) release, as an extension to promises. They were introduced to make promise-based asynchronous programing more readable and easier to perceive. *Async/await* simplifies the syntax used to consume promise-based APIs.

> If you yet to encounter *promises* or you yet to fully understand working with *promises*, you should check out my article on [Making Promises in JavaScript](https://dev.to/imiebogodson/making-promises-in-javascript-3h4f).

Split into two parts; the `async` keyword that is appended in front of a function to make sure the function only returns a promise, and the `await` keyword that can only be used within async functions.

## Async functions

Appending the `async` keyword in front of a function means the function will always return a promise.

```javascript
//A simple function that returns a value
function echo () {
    return 'Hello World';
}

echo();
```
Adding the `async` keyword to the above function will make it return a promise instead of returning the value.

```javascript
//A async function that returns a promise
async function echo () {
    return 'Hello World';
}

echo();
```

### Declaring async functions

Just like we have used function declaration to declare our `echo` function example above, we can also declare our async functions using;

Async function expression, as below:

```javascript
let echo = async function () {
    return 'Hello World';
}

echo();
```

And we can use arrow functions:

```javascript
let echo = async () => {
    return 'Hello World';
}

echo();
```

### Working with the returned value when the promise is fulfilled

We can append the `.then()` method to the promise as we have seen with promise chains, we can use the value to do something else, as seen below:

```javascript
let echo = async () => {
    return 'Hello World';
}

//appending a .then() method to work with the value
echo().then(response => {
    console.log('I am shouting a big ' + response + '!!')
})
```

## The await keyword

> **Thing to seriously note:** The `await` keyword can only be used within async functions. The only time it works on its own is when used with [Javascript modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules).

`await` can be used to call any asynchronous promise-based function that returns a promise. It literally pauses the async function block(not the entire code execution) till the promise returns a value.

Basic syntax:

```javascript
let value = await promise;
```

A basic use case is as seen below:

```javascript
async function sampleFunc () {
    let newPromise = new Promise((resolve, reject) => {
        resolve('The block of code is complete.');
    })

    let displayMessage = await newPromise;
    console.log(displayMessage);
    
}

sampleFunc();
```
The `await` can be used in place of the `.then()` method to handle resolved promises.

```javascript
//A simple promise to fetch data from the jsonplaceholder
fetch("https://jsonplaceholder.typicode.com/users")
	.then(resp => resp.json())
	.then(result => {
		console.log(result)
	})
```

Let us try rewriting the above example with *async/await*:

```javascript
//Using the async/await syntax
async function getData () {
	let fetchedData = await fetch("https://jsonplaceholder.typicode.com/users")
	let parsedData = await fetchedData.json()
	console.log(parsedData)
}
```
We can see that it makes our code clearer and easy to read.

### Using `await` with the `setTimeout` API

```javascript
async function newFunc () {
    let samplePromise = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('I have been resolved')
        }, 5000)
    });

    let getResolved = await samplePromise;
    console.log(getResolved);
}

newFunc();
```

## Using Async/Await with promise features that handle iterables

Given that *async/await* built on top promises, they are compatible with all promise features including the likes of `Promise.all`, `Promise.allSettled`, `Promise.any` and `Promise.race`.

```javascript
const promise1 = new Promise(resolve => {
	setTimeout(() => resolve('success-1'), 2000)
})

const promise2 = new Promise(resolve => {
	setTimeout(() => resolve('success-2'), 7000)
})

const promise3 = new Promise(resolve => {
	setTimeout(() => resolve('success-3'), 9000)
})

const data = await Promise.all([ promise1, promise2, promise3 ]);
console.log(data)
```

Using *async/await* to fetch a set data from an API:

```javascript
const urls = [
  "https://jsonplaceholder.typicode.com/users",
  "https://jsonplaceholder.typicode.com/posts",
  "https://jsonplaceholder.typicode.com/albums",
];

async function grabData () {
		const [ users, posts, albums ] = await Promise.all(
			urls.map(async function (url) {
				const fetchedData = await fetch(url);
				return fetchedData.json();
			}),
			);
		console.log('Users', users),
		console.log('Posts', posts),
		console.log('Albums', albums)
}
```

## Error handling

When handling errors in *async/await* there are different paths to go.

One of the more common ways of handling errors with *async/await* is using the [try...catch](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch) structure. 

Let us try including a `try` and a `catch` block to our `grabData` example above.

```javascript
// We are grabbing a set of data from the jsonplaceholder and logging it in our browser console
const urls = [
  "https://jsonplaceholder.typicode.com/users",
  "https://jsonplaceholder.typicode.com/posts",
  "https://jsonplaceholder.typicode.com/albums",
];

async function grabData () {
	try {
		const { users, posts, albums } = await Promise.all(
			urls.map(async function (url) {
				const fetchData = await fetch(url);
				return fetchData.json();
			}),
			);
		console.log('Users', users),
		console.log('Posts', posts),
		console.log('Albums', albums)
	} catch (err) {
		console.error(err)
	}
}
```

Since *async/await* was create upon promises, you can also follow the hybrid path by chaining the `.catch()` method instead of the [try...catch](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch) structure.

```javascript
const urls = [
  "https://jsonplaceholder.typicode.com/users",
  "https://jsonplaceholder.typicode.com/posts",
  "https://jsonplaceholder.typicode.com/albums",
];

async function grabData () {
		const { users, posts, albums } = await Promise.all(
			urls.map(async function (url) {
				const fetchData = await fetch(url);
				return fetchData.json();
			}),
			);
		console.log('users', users),
		console.log('posts', posts),
		console.log('albums', albums)
}

grabData()
    .catch(err => console.log(err))
```

## Conclusions

My conclusions on using *async/await* are as follows:

1. Using *async/await* makes our asynchronous promise-based API consumption a lot more readable and expressable.

1. A downside to using *async/await* is that it makes our code behave synchronously. `await` literally pauses any code that comes after it till the previous block is done. This can make your program run slower when chaining a set of `await` blocks.

1. Using *async/await* is more a matter of what is comfortable for you and your team.


And that brings us to the end of this article, if you want to check out other articles that I put out you can check out my [blog](https://bitsofjs.hashnode.dev/).

If you have any form of feedbacks please drop it down in the comments, and if you find this article helpful do drop an appreciation.