DEV Community

loading...

Simpler Asynchronous JavaScript code with Async/await

mandareis profile image Amanda ・4 min read

It all started when our class began learning about Promises. In short, a promise is an object that represents awaiting for some operation to complete. There are situations where you might need promises and situations where you will not. For example, if you are looking things up in the DOM or writing to the DOM, this code executes synchronously, meaning our code will block and wait for the result on that particular line.
In the following example, we are doing a simple query for an <h2> element in our document:

let lookUp = document.querySelector("h2")
Enter fullscreen mode Exit fullscreen mode

JavaScript, while it is executing this line, will not be doing anything else. The result will be returned to lookUp before executing the next line. So there are some (most) operations in JS where it will automatically wait for a result.

For other things, such as HTTP requests, JS will not wait for a result, therefore promises are needed to allow JS to continue executing other operations while waiting for results. The following example will only start the operation but will not give us the final result yet.

let promise = fetch("http://example.com")
Enter fullscreen mode Exit fullscreen mode

Async functions help us with the situations where JS will not automatically wait for a result.

For a more complete understanding of promises, as well as this blog post, you can read up on promises here.

I happened to have stumbled upon async functions. Every time I wrote a fetch request inside a function using .then syntax, I would get these faint-colored dots right below the function's name. Upon clicking on these dots, VSCode gives you the option to convert it to an async function, as demonstrated below:

gif shows async function

I have since started using async functions for any HTTP request, but without knowing much of its functionality. I decided to write this blog post as I became curious about the different syntax and if there are benefits to writing async functions. This blog post is a beginner's level explanation of how async functions work. A decent amount of research was done, but as a beginner to JavaScript myself, please feel free to leave any feedback, and I will gladly update this post.

Before we get into the syntax of async/await, we should review what a regular function that will handle asynchronous operation will look like.
The following snippet shows a fetch request using .then syntax:

function sameFunction() {
  return fetch("some_url")
    .then((response) => response.json())
    .then((resultFromResponse) => doSomethingWithResult(resultFromResponse));
}
Enter fullscreen mode Exit fullscreen mode

When using a regular function or non-async function, the code can look somewhat messy and more difficult to understand. Also normal built-in JavaScript syntax such as if statements and for loops become difficult to use.

Async Functions

But what is an async function? This is what I've gathered so far:

  • These are regular functions that will begin with the keyword async.
  • Once marked with async, the function will only return promises now.
  • Once marked with async, the await keyword can be used inside the function to help with handling promises.

In one snippet,

async function someName() {
  let response = await fetch("some_url");
  return await response.json();
}
someName() // => Promise<pending>
Enter fullscreen mode Exit fullscreen mode

Async functions with the await keyword make for much simpler handling of promises. The await keyword does exactly what you might think it would, it waits until a promise is either fulfilled or rejected to resume. Meanwhile, other functions in your code will be allowed to run. Keep in mind that the await keyword only works inside async functions.

Just a heads up, async functions are not currently supported by all browsers, and you might have to use some other tools to make it more widely compatible.

Error handling

The last thing I would like to address is error handling. In regular functions, when handling errors, you need to consider errors that can happen asynchronously. Consider the following example:

function errorHandlingDemoWrong() {
  try {
    fetch("http://thisisjustademo.com/").then((res) => {
      console.log(`status code: ${res.status}`);
    });
  } catch(e) {
    console.log("this will never happen")
  }
}
Enter fullscreen mode Exit fullscreen mode

This function is trying to fetch this domain and because the domain does not exist, it will error out. Because the error occurred inside the promise chain, it will stay within the promise chain. Therefore catch in this snippet will never be executed.

The correct way to handle this error would be to use .catch:

function errorHandlingDemoCorrect() {
  fetch("http://thisisjustademo.com/")
    .then((res) => {
      console.log(`status code: ${res.status}`);
    })
    .catch((err) => {
      console.log(`an error occurred while fetching fake domain: ${err}`);
    });
}
Enter fullscreen mode Exit fullscreen mode

As a beginner, trying to figure out which is the right way to handle errors can be confusing.

This is another way async/await makes writing JavaScript better. In this snippet, all error handling is done with the built-in try/catch syntax, instead of there being two different error handling methods.

async function errorHandlingDemo() {
  try {
    let response = await fetch("http://thisisjustademo.com/");
    console.log(`status code: ${response.status}`);
  } catch (err) {
    console.log(`an error occurred while fetching fake domain: ${err}`);
  }
}
Enter fullscreen mode Exit fullscreen mode

Handling asynchronous code can be very tricky, and async/await makes it easier and more readable.

Discussion

pic
Editor guide