Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript Asynchronous Programming with JavaScript Exploring Async/Await Error Handling with try...catch

Try Catch problem: cannot get the error thrown

In the eventListener, it works when the fetch request successfully. However, when I change the url into a wrong url on purpose, the error won' bubble up as teacher said.

Below is my JS code.

const astrosUrl = 'http://api.open-notify.org/astros.json';
// give it a wrong wiki url on purpose
const wikiUrl = 'https://en.wikipediaa.org/api/rest_v1/page/summary/';
const peopleList = document.getElementById('people');
const btn = document.querySelector('button');

// error handler
async function getJson (url) {
  try {
    const res = await fetch(url)
    console.log('fetch successfully');
    return await res.json()
  } catch (err) {
    console.log(err);
    throw err
  }
}

// Handle all fetch requests
async function getPeopleInSpace (url) {
  const peopleData = await getJson(url) 

  const profilesPromise = peopleData.people.map(async (person, i) => {
    const craft = person.craft
    console.log('profileintome');
    const profile = await getJson(wikiUrl + person.name) 
    console.log('profileinafterme', i,profile);
    return {...profile, craft}
  })
  console.log('promiseprofile', profilesPromise);
  const profiles = await Promise.all(profilesPromise)
  generateHTML(profiles);
}

// Generate the markup for each profile
function generateHTML(data) {
  data.map( person => {
    const section = document.createElement('section');
    peopleList.appendChild(section);
    // Check if request returns a 'standard' page from Wiki
    if (person.type === 'standard') {
      section.innerHTML = `
        <img src=${person.thumbnail.source}>
        <span>${person.craft}</span>
        <h2>${person.title}</h2>
        <p>${person.description}</p>
        <p>${person.extract}</p>
      `;
    } else {
      section.innerHTML = `
        <img src="img/profile.jpg" alt="ocean clouds seen from space">
        <h2>${person.title}</h2>
        <p>Results unavailable for ${person.title}</p>
        ${person.extract_html}
      `;
    }
  });
}

btn.addEventListener('click', async (event) => {
  event.target.textContent = "Loading...";
  try {
    getPeopleInSpace(astrosUrl)
  } catch(err){
// this catch cannot go inside
    peopleList.innerHTML = `<h1>Something went wrong: ${err.message}</h1>`
    console.log(err);
  } finally {
    event.target.remove()
  }
});

3 Answers

Blake Larson
Blake Larson
13,014 Points

You want to use await because if the code doesn't wait for that async function to resolve it doesn't wait to see if an error is thrown in the other functions. It calls the getPeopleInSpace function and since there is no await keyword it immediately goes to the finally block while you are still making api calls behind the scene. That's why when you clicked the button it immediately disappeared.

Thank you, clear and easy to understand.

Blake Larson
Blake Larson
13,014 Points

I added a try catch block in the getPeopleInSpace so you can catch the error thrown in getJson and it creates a error section element.

async function getJson (url) {
  try {
    const res = await fetch(url)
    return res.json()
  } catch (err) {
    throw { msg: 'getJson function error caught' };
  }
}

// Handle all fetch requests
async function getPeopleInSpace (url) {
  try {
    const peopleData = await getJson(url);

    const profilesPromise = peopleData.people.map(async (person, i) => {
      const craft = person.craft;
      const profile = await getJson(wikiUrl + person.name); 
      return {...profile, craft};
    });
    const profiles = await Promise.all(profilesPromise)
    generateHTML(profiles);
  } catch (err) {
      const section = document.createElement('section');
      peopleList.appendChild(section);
      section.innerHTML = `<h1>${err.msg}</h1>`
  }
}

Wondering why try catch cannot catch error in eventListener ?

Even though my callback is an Async Function.

Blake Larson
Blake Larson
13,014 Points

Just need to await the response from getPeopleInSpace because it's an async function.

const astrosUrl = 'http://api.open-notify.org/astros.json';
// give it a wrong wiki url on purpose
const wikiUrl = 'https://en.wikipediaa.org/api/rest_v1/page/summary/';
const peopleList = document.getElementById('people');
const btn = document.querySelector('button');

async function getJson (url) {
  try {
    const res = await fetch(url)
    return res.json()
  } catch (err) {
    throw { msg: 'getJson function error caught' };
  }
}

// Handle all fetch requests
async function getPeopleInSpace (url) {
  try {
    const peopleData = await getJson(url);

    const profilesPromise = peopleData.people.map(async (person, i) => {
      const craft = person.craft;
      const profile = await getJson(wikiUrl + person.name); 
      return {...profile, craft};
    });
    const profiles = await Promise.all(profilesPromise)
    generateHTML(profiles);
  } catch (err) {
      throw err.msg;
  }
}

// Generate the markup for each profile
function generateHTML(data) {
  data.map( person => {
    const section = document.createElement('section');
    peopleList.appendChild(section);
    // Check if request returns a 'standard' page from Wiki
    if (person.type === 'standard') {
      section.innerHTML = `
        <img src=${person.thumbnail.source}>
        <span>${person.craft}</span>
        <h2>${person.title}</h2>
        <p>${person.description}</p>
        <p>${person.extract}</p>
      `;
    } else {
      section.innerHTML = `
        <img src="img/profile.jpg" alt="ocean clouds seen from space">
        <h2>${person.title}</h2>
        <p>Results unavailable for ${person.title}</p>
        ${person.extract_html}
      `;
    }
  });
}

btn.addEventListener('click', async (event) => {
  event.target.textContent = "Loading...";
  try {
    await getPeopleInSpace(astrosUrl) //<--- ****Await response****
  } catch(err){
// this catch cannot go inside
    peopleList.innerHTML = `<h1>Something went wrong: ${err}</h1>`
  } finally {
    event.target.remove()
  }
});

Is it necessary to await an Async function, even if I don't need to get the resolve value?