Why is async() not returning the fetched data?

Why is async() not returning the fetched data?

·

3 min read

Problem:

I tested my async function that fetch data from a url, it works correctly. But it doesn't return the fetched data, why?

Consider a simple example in code-block-1 that fetch an array from url.

// code-block-1
// App.js 
const url = "https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json"

const getData = async () => {
  const response = await fetch(url);
  const quotes = await response.json();
  console.log(quotes);
  return quotes
}

console.log(quotes) is to check if quotes array is fetched from the url as expected.

fetchProblem1.png

After checking the console (shown as image above), I am confident that my simple getData() works. In order to keep my code clean in App.js, I transfer the above code to a separated module getData.js.

Updated getData.js and App.js are as in code-block-2 and code-block-3:

// code-block-2
// getData.js 
const url = "https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json"

const getData = async () => {
  const response = await fetch(url);
  const quotes = await response.json();
  return quotes
}
//code-block-3
// App.js 
import getData from "./getData";

const quotes = getData()
console.log(quotes)

So quotes in code-block-3 should contain the array returned by the fetch() request, shouldn't it? Let's check the console.

fetchProblem2.png

Huh? How comes it's a Promise object???

Why did it happen?

Gotcha #1

getData() is an async function, and every async function returns a Promise object.

So the gotcha here is:

  • in code-block-1, console logging the quotes shows an array of data is correctly fetched.
  • since getData() returns quotes, I should get fetched array in code-block-3.

BUT, because it's an async function, it returns a Promise object instead of the fetched array as expected.

So where is the fetched array, and what's the solution?

Solution

When we dig deeper into the Promise object, here's what we see:

fetchProblem3.jpg

Indeed the quotes array was fetched as shown in the orange box above. How do we access it? Because getData() returns a Promise, we can use .then() to access the fetched data from the Promise object.

// code-block-4
// App.js
import getData from "./getData";

getData().then((data) => {
  var quotes = data.quotes;
});

In code-block-4, the fetched array is assigned to a global variable quotes. Note that in this example, const and let do not work because they define variables in "block scope", which means variables defined by const and let do not exist outside the block scope.

Or if you are using React, you can assign the fetched array to a state variable:

// code-block-5
// App.js
import { useState } from "react";
import getData from "./getData";

const [quotes, setQuotes] = useState([]);

getData().then((data) => {
  setQuotes(data.quotes);
});

In code-block-5, the fetched quotes array is assigned to the state variable quotes via setQuotes().

The key here is, whatever you want to do with the fetched data, do it inside callback function within the .then() block. Ok, but why?

Gotcha #2

It's tempting to think of assigning the result of .then() to a variable, like in code-block-6 below:

// code-block-6
// App.js
import getData from "./getData";

const quotes = getData().then((data) => data.quotes)
console.log(quotes)

This time quotes variable should contain the fetched array is it? You guessed it, the answer is no...

fetchProblem4.png

The above picture shows, we are getting a Promise object, AGAIN!!!! What happened?

It is because the return value of a .then() call is again a Promise object. So we are back to square 1.

Summary

  • Both async function and .then() return a Promise object which contains the fetched data, INSTEAD OF returning the fetched data itself.
  • Access the data and do something with it within the .then() callback function as shown in code-block-4 and code-block-5 above.

Further readings: