Skip to main content Accessibility Feedback

How to use async and await with vanilla JavaScript

You may have seen async and await before and been confused about what they do or why you would use them. Today, I’m going to demystify things a bit with some practical examples.

What async and await do

The async operator turns a traditional function into a Promised-based, asynchronous one.

The await operator tells a script to wait for a Promise to resolve before moving on (kind of like .then() does). When used with a variable operator (like var or let), it assigns the response from the promise to the variable rather than the Promise itself.

The await operator can only be used inside of an async function.

The async and await operators are useful in letting you write Promise-based functions the same way you would write synchronous ones.

Confused yet? Let’s clear things up with a real example.

Using data from one fetch() request to make another

Yesterday, we looked at how to use data from one fetch() request to make another, and then combine all of the data together.

This was the end result.

var getPost = function () {

	var post;

	// Call the API
	fetch('https://jsonplaceholder.typicode.com/posts/5').then(function (response) {
		if (response.ok) {
			return response.json();
		} else {
			return Promise.reject(response);
		}
	}).then(function (data) {

		// Store the post data to a variable
		post = data;

		// Fetch another API
		return fetch('https://jsonplaceholder.typicode.com/users/' + data.userId);

	}).then(function (response) {
		if (response.ok) {
			return response.json();
		} else {
			return Promise.reject(response);
		}
	}).then(function (userData) {
		console.log(post, userData);
	}).catch(function (error) {
		console.warn(error);
	});

};

getPost();

Let’s use async and await to write this script a different way.

Using async and await with fetch() to call an API

The first thing we’ll do is add the async operator before our function operator. This turns the function into an asynchronous, Promise-based one.

var getPost = async function () {
	// Code goes here...
};

getPost();

Next, we’ll make our fetch() call with the API. Rather than using then(), though, we’ll prefix it with await and assign it to a variable.

Now, our async getPost() function will wait until fetch() returns its response to assign a value to postResp and run the rest of the script. And instead of assigning the Promise that fetch() returns, it will assign the actual response it gets back.

var getPost = async function () {

	// Get the post data
	var postResp = await fetch('https://jsonplaceholder.typicode.com/posts/5');

};

getPost();

Next, we can use the json() method on that response to get the actual data. The json() method is also Promise-based, so we’ll need to use await with that one, too.

var getPost = async function () {

	// Get the post data
	var postResp = await fetch('https://jsonplaceholder.typicode.com/posts/5');
	var post = await postResp.json();

};

getPost();

We now have data back, assigned to post. We can use the post.userId to make our second API call.

We’ll again prefix it with await, then use the json() method to get the data from it.

When both API calls have completed, we can log the post and author data into the console.

var getPost = async function () {

	// Get the post data
	var postResp = await fetch('https://jsonplaceholder.typicode.com/posts/5');
	var post = await postResp.json();

	// Get the author
	var authorResp = await fetch('https://jsonplaceholder.typicode.com/users/' + post.userId);
	var author = await authorResp.json();

	console.log(post, author);

};

getPost();

Here’s a demo in CodePen

As you can see, this has a nice, simple, readable syntax. But there’s an issue with this setup.

Error Handling

The current setup will break very ungracefully if there’s an error with the API response.

For example, if you spelled the endpoint /postses instead of /posts, post and author will be undefined. If you misspelled the URL itself, or if the API was down, the script would break before getting to the console.log() part.

var getPost = async function () {

	// Get the post data
	var postResp = await fetch('https://jsonplaceholder.typicode.com/postses/5');
	var post = await postResp.json();

	// Get the author
	var authorResp = await fetch('https://jnosplaceholder.typicode.com/users/' + post.userId);
	var author = await authorResp.json();

	console.log(post, author);

};

getPost();

Here’s an example of it failing.

On Monday, we’ll look at how to handle errors.

Browser compatibility

The async and await methods work in all modern browsers, but have no IE support. They cannot be polyfilled, and must be transpiled using a tool like Babel if you want them to run in older browsers.