skip to Main Content

I’m looking to return a string in a html tag. (Chuck Norris joke from an API)
I succeed to display the value if I ask directly to display it in the function body.

But I don’t succeed to return a string to display it later. I want to call only once the function so I can display the string in several areas.

What is working:

document.querySelector('#bt_funFact').addEventListener('click', async () => {
  norrisRandom();
})

async function norrisRandom() {
  fetch('https://api.chucknorris.io/jokes/random')
    .then(res => res.json())
    .then(data => {
      console.log(data.value)
      document.getElementById('funFact').innerHTML = data.value;
    })
}

But if I try to return the value like below, I get "[object Promise]" in html.

document.querySelector('#bt_funFact').addEventListener('click', async () => {
  document.getElementById('funFact').innerHTML = norrisRandom();
})

async function norrisRandom() {
  fetch('https://api.chucknorris.io/jokes/random')
    .then(res => res.json())
    .then(data => {
      console.log(data.value)
      return data.value;
    })
}

I can’t figure out why it displays in function body and not by returning the value.

3

Answers


  1. The issue you’re facing is because the norrisRandom() function is asynchronous and returns a promise. When you try to set the innerHTML directly with norrisRandom(), you are assigning the promise object to it, which is why you see "[object Promise]" in the HTML. Try this

    document.querySelector('#bt_funFact').addEventListener('click', async () => {
      const joke = await norrisRandom();
      document.getElementById('funFact').innerHTML = joke;
    });
    
    async function norrisRandom() {
      const response = await fetch('https://api.chucknorris.io/jokes/random');
      const data = await response.json();
      return data.value;
    }
    Login or Signup to reply.
  2. You don’t seem to understand what the async keyword is doing, so:

    Declaring a function async makes it possible to use await inside of it.

    This makes it possible to write asynchronous code in a synchronous fashion:

    async function fn() {
        await one()
        await two()
        await three()
        console.log("done!")
    }
    

    Is functionally equivalent to:

    function fn() {
        return one()
            .then(() => {
                return two()
            })
            .then(() => {
                return three()
            })
            .then(() => {
                console.log("done!")
            })
    }
    

    Notice how the async function is much easier to read?

    So there’s no point in declaring a function async when you’re not going to use the await keyword inside of it!

    Let’s start by fixing your norrisRandom function:

    async function norrisRandom() {
      const res = await fetch('https://api.chucknorris.io/jokes/random')
      const data = await res.json()
    
      return data.value  
    }
    

    Then use await inside your click handler like this:

    document.querySelector('#bt_funFact').addEventListener('click', async () => {
        document.getElementById('funFact').innerHTML = await norrisRandom();
    })
    
    Login or Signup to reply.
  3. The event listener should use await to extract the value from the promise returned by norrisRandom(). Your code is putting the Promise itself in the inner HTML.

    norrisRandom() doesn’t need to be declared async, since .then() returns a promise already. But you need to return the value of the .then() chain.

    document.querySelector('#bt_funFact').addEventListener('click', async () => {
      document.getElementById('funFact').innerHTML = await norrisRandom();
    })
    
    function norrisRandom() {
      return fetch('https://api.chucknorris.io/jokes/random')
        .then(res => res.json())
        .then(data => {
          console.log(data.value)
          return data.value;
        })
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search