DEV Community

Cover image for The saga of Javascript errors and async/await
Darlan Alves
Darlan Alves

Posted on • Edited on

The saga of Javascript errors and async/await

We went full circle with error management in Javascript!

Long ago, before AJAX was a thing, JS was pretty much synchronous and linear. Still, we had to handle errors, so we used try/catch:

function divide(a, b) {
  return a / b;
}

try {
  divide(1, 0);
} catch (error) {
  // uh, oh
}
Enter fullscreen mode Exit fullscreen mode

But then Ajax came along, along with a lot of other async API's. We started using more callbacks for our error management:

const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function (content) { /* ... */ };
xhr.onerror = function (error) { /* ... */ };
Enter fullscreen mode Exit fullscreen mode

And then Node.JS came along, with a callback based API. Error handling was quickly turning into callback hell:

fs.readFile('foo.txt', function (error, fileContent) {
  fs.writeFile('bar.txt', fileContent, function (otherError) {
    // ...
  });
});
Enter fullscreen mode Exit fullscreen mode

And then... Then we created Promise to make it more readable and consistent (apparently):

// Fetch full content of the first item found
fetch('www.example.com/items')
  .then(response => response.json())
  .then(response => 
    fetch('www.example.com/items/' + response[0].id)
  )
  .catch(error => {
    // Wait! Is this from the first or the second request?
  });
Enter fullscreen mode Exit fullscreen mode

A bit better, but we still need sequential execution, and soon we get into promise hell.

async/await to the rescue

Okay, we need to fix this.
So we decided to introduce a new syntax that will internally wait for a promise resolution and clean up the code. async/await is the solution:

// Fetch full content of the first item found
const items = await fetch('www.example.com/items')
const firstItem = (await items.json())[0]
const fullContent = await fetch('www.example.com/items/' + firstItem.id)
Enter fullscreen mode Exit fullscreen mode

But wait! What if the first or the second request fails?
Don't worry! We have a solution for that too!

Behold the full circle of errors: try/catch 😆

try {
  // Fetch full content of the first item found
  const items = await fetch('www.example.com/items')
  const firstItem = (await items.json())[0]
  const fullContent = await fetch('www.example.com/items/' + firstItem.id)
} catch (error) {
  // Wait! Is this from the first or the second request?
}
Enter fullscreen mode Exit fullscreen mode

Pitfalls, pitfalls everywhere!

Cool! Try/catch is now async. YAY!

But what happens if I forget to use await? Well, more errors for you!

If you actually want to return a promise from a function but still handle errors, it looks like this:

try {
  return fetchAndParse('www.example.com/items.json')
} catch (error) {
  // synchronous errors end up here
}
Enter fullscreen mode Exit fullscreen mode

Can you guess what happens if fetchAndParse returns a rejected promise?

function fetchAndParse() {
  return new Promise((resolve, reject) => {
    reject(new Error('Nope!'));
  };
}
Enter fullscreen mode Exit fullscreen mode

And the answer is: nothing. Your try/catch block won't do anything to catch that error.
Why? Because you need the magic word in front of the function call to "connect" the chain of promises:

try {
  return await fetchAndParse('www.example.com/items.json')
} catch (error) {
  // the rejection error ends up here
}
Enter fullscreen mode Exit fullscreen mode

See the difference? Subtle, but quite important!

Conclusion

So basically, if you want to use async/await, you need to wrap everything with try/catch, and you must ensure every single promise has an await in front of it.

Otherwise, JS will just ignore the errors and continue like nothing happened.

Image of Datadog

The Essential Toolkit for Front-end Developers

Take a user-centric approach to front-end monitoring that evolves alongside increasingly complex frameworks and single-page applications.

Get The Kit

Top comments (0)

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay