Simplify Asynchronous JavaScript with async/await

Hero image for Simplify Asynchronous JavaScript with async/await. Image by Levi Meir Clancy.
Hero image for 'Simplify Asynchronous JavaScript with async/await.' Image by Levi Meir Clancy.

As a web developer, working with asynchronous code is an inevitable part of building modern web applications, allowing for nonblocking operations to allow processes to continue whilst waiting for a response from elsewhere (for example, from an API or database query).

JavaScript already provides us with several asynchronous strategies, including Callbacks and Promises, but these can sometimes be difficult to work with and can lead to complex code. That's where async/await comes in it simplifies asynchronous JavaScript code and makes it more readable and maintainable. In this article, I intend to explore how to use async/await, compare it with other asynchronous strategies, and discuss potential issues.


What is async/await?

Async/await is a relatively new addition to JavaScript, introduced earlier this month as part of ES2017 (ES8). It provides a simpler and more concise syntax for writing asynchronous code, and is built on top of Promises to provide a way to write asynchronous code that looks and behaves more like synchronous code. Async/await allows us to write asynchronous code using a more linear approach we can write code that waits for an asynchronous operation to complete before moving on to the next line of code, without the need for nested callbacks.


How does async/await work?

Async/await works by using two new keywords: async and await. The async keyword is used to mark a function as asynchronous, whilst the await keyword is used to wait for a Promise to resolve. When using async/await, we write asynchronous code in a synchronous style, without blocking the main thread.

Basic Example

Let's start with a simple example to illustrate how async/await works. Consider the following function, which returns a Promise that resolves after a certain time:

const wait = (ms) => {  return new Promise((resolve) => setTimeout(resolve, ms));};

We could use this function to wait for a certain amount of time, like this:

wait(1000).then(() => {  console.log('Waited for 1 second');});

Using async/await, we can achieve the exact same outcome like this:

const doSomething = async () => {  await wait(1000);  console.log('Waited for 1 second');};doSomething();

The async keyword is used to mark the function as asynchronous, and the await keyword is used to wait for the Promise to resolve before moving on to the next line of code. This makes the code much easier to read and understand.

Advanced Example

I admit, that's not a very compelling example so let's delve into something a little juicier. Consider the following function that uses Promises to fetch data from an API:

const fetchUser = (id) => {  return fetch(`https://jsonplaceholder.typicode.com/users/${id}`).then(    (response) => response.json()  );};

I've used a similar example before when talking about promises. We could call it to grab the user's name from the API using a function that looks a little like this:

fetchUser(1).then((user) => {  console.log(user.name);});

Using async/await, we can write the same code like this:

const doSomethingElse = async () => {  const user = await fetchUser(1);  console.log(user.name);};doSomethingElse();

This code is much easier to read and understand using async/await. We use await to wait for the Promise to resolve, and then we can use the returned value directly. Whilst working on an unfamiliar codebase, the async/await syntax is going to make it much more obvious, much sooner, what's going on.


Callbacks vs. Promises vs. async/await

Before async/await was introduced, developers had to use either callbacks or Promises to handle asynchronous code. Whilst both of these methods work, they can lead to complex and hardtoread code.

Callbacks are the original way of handling asynchronous code in JavaScript. Callbacks work by passing a function as an argument to another function, which is called when the operation completes. Whilst this method works, it can lead to a lot of nested callbacks, which can be hard to read and debug.

Promises were introduced to simplify asynchronous code by providing a way to chain asynchronous operations. Promises work by returning an object that represents the eventual completion (or failure) of an asynchronous operation. Promises can be chained together using the .then() and .catch() methods to handle the resolution or rejection of the Promise. While Promises are a significant improvement over callbacks, they can still lead to complex and verbose code.

Async/await provides a simpler and more concise syntax for handling asynchronous code. Async/await is built on top of Promises, so it provides all of the benefits of Promises (such as chaining and error handling) but with a more readable and synchronousstyle syntax.


Potential Issues with async/await

Of course, it's still very early days for the adoption of async/await, and browser support is still a little way away from being ready for prime time. However, whilst async/await provides a simpler and more concise way to write asynchronous code, I can foresee some potential issues that developers may come across.

One potential issue is that async/await can lead to performance issues if not used correctly. Since async/await is built on top of Promises, it is important to ensure that Promises are properly optimised and that unnecessary Promise chaining is avoided.

Another potential issue is that async/await can lead to code that is harder to debug. Since async/await hides the asynchronous nature of the code, it can be harder to understand what is happening when errors occur. For this reason, much like with promises, it is really important that developers handle the error states that might arise.


Wrapping up

To offer some conclusion: Async/await is an exciting new feature and a powerful addition to JavaScript that simplifies asynchronous code by providing a more concise and synchronousstyle syntax. It is built on top of Promises and provides all of the benefits of Promises with a simpler and more readable syntax. Although async/await can lead to performance and debugging issues if not used correctly, it is an essential tool for writing modern and maintainable web applications.

I'm looking forward to getting properly stuck in with my next project!


Categories:

  1. ES6
  2. Front‑End Development
  3. JavaScript