Refactoring a Plain Promise to Async / Await

Cathy D'Onofrio
3 min readDec 21, 2020

--

Photo by James Harrison on Unsplash

When I was doing some research for a project I’m working on, I stumbled on the async/await syntax, which is the ES2017 way or writing a promise based fetch call. At Flatiron, had been taught using plain promises, although some of my classmates taught themselves async/await.

Async/await is syntactic sugar written on top of promises. It makes asynchronous code appear more synchronous. Below, I’ll show how to refactor a regular promise to async/await.

Plain Promises

As a refresher — whenever we make a request with fetch, it returns a promise. The promise is resolved with an object that represents the request.

To know that the promise has been resolved, we chain on a .then statement. Here, we receive it as a ‘response’ argument and call .json() on it to return another promise.

To then get access to the final json data, we chain on another .then on the returned promise. In the example below, I’m logging the data to the console to see what the object looks like.

const fetchCatFacts = () => {
fetch('https://cat-fact.herokuapp.com/facts')
.then(response => response.json())
.then(jsonData => console.log(jsonData))
}
fetchCatFacts();

Output:

Refactoring to async / await, step by step

The new async/await syntax makes it easier to work with promises. It will still return a promise and define a block of code that will execute only after the request is resolved. However, the new syntax makes it visually appear to be synchronous, and therefore easier to work with.

To refactor it, identify the codebase that is making a request and put ‘async’ in front of the function that will be asynchronous. Async always returns a promise.

const fetchCatFacts = async () => {
//...
}

Next, identify the promises made, remove the .then() chain, and put ‘await’ in front of them. Assign these promises to variables. Note, ‘await’ will only work within an ‘async’ function.

const fetchCatFacts = async () => {
const response = await fetch('https://cat-fact.herokuapp.com/facts');
const json = await response.json();
}

Finally, request how you’d like the data to be parsed and invoke it. It will return the same array of objects as the old syntax, but it looks much cleaner.

Final refactor:

const fetchCatFacts = async () => {
const response = await fetch('https://cat- fact.herokuapp.com/facts');
const json = await response.json();

console.log(json); //promise returned, logs array of objects
}
fetchCatFacts();

Result:

Plain Promise refactored as async/await produces the same results

Below, I’ve updated my console log to show just the array of cat facts. To me, this looks much easier than if it had been written as a regular promise.

Original way:

const fetchCatFacts = () => {
fetch('https://cat-fact.herokuapp.com/facts')
.then(response => response.json())
.then(jsonData => console.log(jsonData.map(data => data.text)))
}
fetchCatFacts();

With async / await:

const fetchCatFacts = async () => {

const response = await fetch('https://cat-fact.herokuapp.com/facts');

const json = await response.json();
console.log(json.map(data => data.text))}fetchCatFacts();

Output for both:

Takeaway

Since these are relatively simple examples, you may not be motivated to make the switch over to async/await. Maybe plain promises are still easier to read if that’s what you’re accustomed to. And that’s perfectly fine — since async /await is syntactic sugar written on top of promises, they do the same thing!

However, it’s still worth learning for instances where your requests get more more complicated — think conditionals, error handling, etc. As is the case in other areas in programming, it’s best to keep things clean, readable and scalable, and I think that this approach certainly streamlines things.

I hope this overview encourages you to consider using async/await in your next project!

--

--

Cathy D'Onofrio

Full stack developer based in Brooklyn, NY