Async Await
Tags: webdev, javascript, beginners, programming
Published: 2023-06-26 18:02:23

## What is Async Await

`async`/`await` is a language feature introduced in ECMAScript 2017 (AKA ES8) that makes it easier to work with asynchronous code in JavaScript. It allows you to write asynchronous code that looks and behaves like synchronous code, using the `await` keyword to pause execution until a Promise is resolved.

`async`/`await` is a syntactic sugar over the promises. It makes asynchronous code look like synchronous code. It is a new way to write asynchronous code in JavaScript.

Let's see them individually.

### `async`

The `async` keyword is used to declare an asynchronous function. What happens when you use the `async` keyword?

It executed asynchronously, meaning that it doesn't block the execution of the program while it's waiting for a certain task to complete. Instead, it returns a Promise that represents the result of the asynchronous operation.

`async` functions are typically used when dealing with time-consuming operations such as network requests, file I/O, or database queries, where waiting for the result would block the execution of the program. By using `async` functions, you can avoid blocking and allow the program to continue executing other tasks while waiting for the result.

It Allows you to write promises-based code as if it was synchronous. It ensures that the execution thread is not being broken. The event loop is used for its asynchronous operation. A value is always returned by `async` functions. It guarantees that promises be fulfilled, and if they are not, JavaScript automatically wraps them in promises that are resolved with their values.

```js
async function myFunction() {
	return "Hello World";
}
```

The above function returns a promise. The promise is resolved with the value `"Hello World"`.

And in the arrow function:

```js
const myFunction = async () => {
    return "Hello World";
};
```

### `await`

`await` keyword is used to wait for a Promise to resolve before proceeding to the next line of code. It can only be used inside an asynchronous function (a function that has been declared with the `async` keyword).

When an `async` function encounters an `await` keyword, it pauses its execution until the Promise that is being awaited has been resolved. The value of the resolved Promise is then returned and assigned to the variable that follows the `await` keyword.

Here's an example of how `await` can be used:

```js
async function getData() {
	const response = await fetch("https://example.com/data");
	const data = await response.json();
	return data;
}

getData().then((data) => {
	console.log(data);
});
```

In the example above, the `getData` function is declared as `async`, which allows us to use the `await` keyword inside it. The function first makes a network request to fetch some data from the specified URL. We then wait for the response to come back using `await`, and then we wait again for the data to be parsed into a JSON object. Finally, we return the parsed data from the function.

When we call `getData()`, it returns a Promise that resolves to the parsed data. We can then use `.then()` to log the data to the console once it's been resolved.

## `async`/`await` vs `promises`

`async`/`await` is modified version (wrapper) of promises. `async`/`await` just replaces the `.then()` and `.catch()` methods with `await` keyword and `try` and `catch` blocks. It is a syntactic sugar over promises. It makes asynchronous code look like synchronous code. It is a new way to write asynchronous code in JavaScript.

### `async`/`await`

```js
async function myFunction() {
	const fetchData = async () => {
		const res = await fetch(resource);
		const data = await res.json();
		return data;
	};

	const result = await fetchData(); // wait till the promise resolves (*)

	console.log(result); // "Promise was resolved"
}
```

### promises

```js
function myFunction() {
	const fetchData = () => {
		return fetch(resource)
			.then((res) => res.json())
			.then((data) => data);
	};

	fetchData().then((result) => console.log(result)); // "Promise was resolved"
}
```

Both the above code snippets do the same thing. The only difference is that the `async`/`await` version is easier to read and write. But in some cases, where I need to run multiple promises in parallel, I prefer to use promises instead of `async`/`await`. Because `async`/`await` will wait for the previous promises to resolve before moving to the next line of code. But in promises, I can run multiple promises in parallel like [this](#async--await-with-promiseall-and-promisesettleall-methods)

## Examples

### HTTP requests with `async`/`await`

Here's an example of using `async`/`await` to make an HTTP request:

```js
// to use async/await, you must use a function that is labeled as `async`, like this:
async function getData() {
	try {
		const response = await fetch("https://example.com/");
		// `await` will pause the execution of the function until the Promise is resolved
		const data = response.json();
		console.log(data);
	} catch (error) {
		// if there is an error, it will be caught here
		console.error(error);
	}
}

getData(); // calling the function
```

In this example, we define an `async` function called `getData`. Inside the function, we use the `await` keyword to pause execution until the fetch Promise is resolved.

If there is an `error` making the request, the catch block will be executed.

`async`/`await` makes it easier to work with asynchronous code in JavaScript and can help make your code more readable and maintainable. It is particularly useful for working with Promises and is widely used in modern JavaScript code.

:::info

`async`/`await` is a language feature that is built on top of Promises. It is not a replacement for Promises. It is a syntactic sugar that makes asynchronous code look and behave like synchronous code.

If you are new to Promises, you should read the [Promises](/docs/languages/js/advance/async-code/promises) article first.

:::

### `async`/`await` with `Promises`

Here's an example of how to use `async`/`await` with a `Promise`:

```js
async function getData() {
	try {
		const response = await fetch("https://example.com/");
		const data = await response.json();
		return data;
	} catch (error) {
		console.error(error);
	}
}

getData()
	.then((data) => {
		console.log(data);
	})
	.catch((error) => {
		console.error(error);
	});
```

In this example, we define an `async` function called `getData`. The `await` operator is used to wait for the resolved value of a Promise. In this case, we use it to wait for the `fetch` function to complete and for the `json` method to complete.

If the Promise is rejected, the `catch` block will be executed.

### `async`/`await` with `for` loops

Here's an example of how to use `async`/`await` with a `for` loop:

```js
async function getData() {
	try {
		const response = await fetch("https://example.com/");
		const data = await response.json();
		return data;
	} catch (error) {
		console.error(error);
	}
}

async function getMultipleData() {
	const data = [];
	for (let i = 0; i < 5; i++) {
		const response = await getData();
		data.push(response);
	}
	return data;
}

getMultipleData()
	.then((data) => {
		console.log(data);
	})
	.catch((error) => {
		console.error(error);
	});
```

In this example, we define an `async` function called `getData`. The `await` operator is used to wait for the resolved value of a Promise. In this case, we use it to wait for the `fetch` function to complete and for the `json` method to complete.

If the Promise is rejected, the `catch` block will be executed.

### `async`/`await` with `Promise.all()` and `Promise.settleAll()` methods

Imagine a situation where you have to make multiple HTTP requests and put `await` in front of each request, in result you have to wait for all of them to complete sequentially, and it would take a lot of time, as you can see in the example below:

```js title="sequential requests"
async function getData() {
	try {
		const users = await getUser();
		const posts = await getPosts(); // wait for the previous request to complete
		const comments = await getComments(); // wait for the previous request to complete
		const followers = await getFollowers(); // vice versa
		const following = await getFollowing();
		const likes = await getLikes();

		return {
			users,
			posts,
			comments,
			followers,
			following,
			likes,
		};
	} catch (error) {
		console.error(error);
	}
}
```

You can see that we have to wait for each request to complete before moving on to the next one. This is where `Promise.all` comes in handy.

#### `Promise.all`

It allows you to hit multiple async processes at the same time (in parallel) and wait for all of them to complete. Here's an example:

```js title="parallel requests"
async function getData() {
	try {
		const usersPromise = getUser(); // no await here
		const postsPromise = getPosts(); // no await here
		const commentsPromise = getComments(); // vice versa
		const followersPromise = getFollowers();
		const followingPromise = getFollowing();
		const likesPromise = getLikes();

		// wait for all promises to resolve, and then destructure the result
		const [users, posts, comments, followers, following, likes] =
			await Promise.all([
				usersPromise,
				postsPromise,
				commentsPromise,
				followersPromise,
				followingPromise,
				likesPromise,
			]);

		/**
		 * or you can use the following syntax if you don't need to use the promises again
		 * which is more concise and readable, and I prefer this syntax
		 *
		 * const [users, posts, comments, followers, following, likes] = await Promise.all([
		 *     getUser(),
		 *     getPosts(),
		 *     getComments(),
		 *     getFollowers(),
		 *     getFollowing(),
		 *     getLikes(),
		 *  ]);
		 *
		 */

		return {
			users,
			posts,
			comments,
			followers,
			following,
			likes,
		};
	} catch (error) {
		console.error(error);
	}
}
```

In this example, we use `Promise.all` to wait for all the promises to be resolved and then we destructure the array to get the resolved values. These are parallel requests, which means that the requests are made at the same time.

#### `Promise.allSettled`

But `Promise.all` has a problem, imagine a situation where one of the promises is rejected, in this case, the whole promise will be rejected and the `catch` block will be executed. If we want to get the resolved values, and ignore the rejected ones, we can use `Promise.allSettled`:

```js
async function getData() {
	try {
		const [users, posts, comments, followers, following, likes] =
			await Promise.allSettled([
				getUser(),
				getPosts(),
				getComments(),
				getFollowers(),
				getFollowing(),
				getLikes(),
			]);

		return {
			users,
			posts,
			comments,
			followers,
			following,
			likes,
		};
	} catch (error) {
		console.error(error);
	}
}
```

In this example, we use `Promise.allSettled` to wait for all the promises to be resolved or rejected and then we destructure the array to get the resolved values.

### `async`/`await` in series

`Promise.all` and `Promise.allSettled` are useful if all the promises are independent of each other, but if you have a situation where you have to wait for one promise to be resolved before moving on to the next one. You can also use `Promise.all`, or `Promise.allSettled` for few promises, and then await the next promise, as shown in the example below:

```js
async function getData() {
	try {
		const [users, posts, comments] = await Promise.all([
			getUser(),
			getPosts(),
			getComments(),
		]);

		const followers = await getFollowers();
		const following = await getFollowing();
		const likes = await getLikes();

		return {
			users,
			posts,
			comments,
			followers,
			following,
			likes,
		};
	} catch (error) {
		console.error(error);
	}
}
```

In this example, we use `Promise.all` to wait for the first three promises to be resolved, and then we await the next three promises.

## Conclusion

In this article, we learned about `async`/`await` and how to use it with Promises. We also learned how to use `async`/`await` with `for` loops and how to use `async`/`await` with `Promise.all` and `Promise.allSettled` methods.