Get started with 33% off your first certification using code: 33OFFNEW

The Differences Between async and await in JavaScript

5 min read
Published on 7th June 2024

JavaScript, being a highly versatile language, has evolved significantly since its inception. One of the major milestones in its evolution is the introduction of async and await keywords in ECMAScript 2017. These keywords have revolutionized how developers handle asynchronous operations, making the code more readable and easier to manage. In this article, we'll delve into the differences between async and await, how they work, and provide examples to illustrate their usage.

Understanding Asynchronous JavaScript

Before diving into async and await, it's crucial to understand the concept of asynchronous programming in JavaScript. Asynchronous programming allows a program to perform long-running tasks without blocking the main execution thread. This is particularly useful in web development, where you often need to perform tasks like fetching data from an API, reading files, or handling user interactions.

JavaScript traditionally handled asynchronous operations using callbacks and promises. While these methods work, they can lead to complex and hard-to-read code, especially when dealing with multiple asynchronous tasks. This is where async and await come in, providing a more straightforward and readable way to work with asynchronous code.

What is async?

The async keyword is used to declare an asynchronous function. When a function is defined with async, it automatically returns a promise, and the return value of the function is wrapped in a resolved promise. Here's an example:

async function fetchData() {
    return "Data fetched";
}

fetchData().then(data => console.log(data));
// Output: Data fetched

In the example above, fetchData is an asynchronous function that returns a promise. When we call fetchData(), it returns a promise that resolves to the string "Data fetched".

Key Points About async

  1. Automatic Promises: An async function always returns a promise, regardless of whether it explicitly returns a promise or not.
  2. Error Handling: Inside an async function, you can use try...catch blocks to handle errors more gracefully, similar to synchronous code.
  3. Simplifies Code: async functions help simplify the syntax and improve the readability of asynchronous code.

What is await?

The await keyword is used inside an async function to pause the execution of the function until a promise is resolved. This makes the code look and behave like synchronous code, even though it's handling asynchronous operations. Here's an example:

async function fetchData() {
    let data = await new Promise(resolve => setTimeout(() => resolve("Data fetched"), 1000));
    console.log(data);
}

fetchData();
// Output (after 1 second): Data fetched

In this example, the await keyword pauses the execution of the fetchData function until the promise returned by setTimeout is resolved. This allows us to write asynchronous code that looks synchronous, making it easier to read and understand.

Key Points About await

  1. Used Inside async Functions: await can only be used inside async functions. If you try to use it outside an async function, you'll get a syntax error.
  2. Pauses Execution: await pauses the execution of the async function until the promise is resolved, making it easier to write and reason about asynchronous code.
  3. Error Handling: Similar to async, you can use try...catch blocks with await to handle errors more gracefully.

Differences Between async and await

While async and await are often used together, they serve different purposes and have distinct differences.

1. Purpose

  • async: Used to declare a function as asynchronous. It ensures that the function returns a promise.
  • await: Used to pause the execution of an async function until a promise is resolved.

2. Return Value

  • async: An async function always returns a promise. If the function returns a value, that value is wrapped in a resolved promise.
  • await: The await keyword returns the resolved value of the promise. It can only be used inside async functions.

3. Error Handling

  • async: Errors inside an async function are propagated as rejected promises, which can be caught using catch or with try...catch blocks inside the function.
  • await: Errors in a promise being awaited are propagated to the surrounding async function, allowing them to be caught using try...catch blocks.

4. Execution Flow

  • async: Declares the function as asynchronous and allows the use of await inside it.
  • await: Pauses the execution of the async function until the awaited promise is resolved, making asynchronous code look synchronous.

Practical Examples

To illustrate the differences and usage of async and await, let's look at some practical examples.

Example 1: Fetching Data from an API

Let's fetch data from a public API using async and await:

async function getUserData(userId) {
    try {
        let response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`);
        let data = await response.json();
        console.log(data);
    } catch (error) {
        console.error("Error fetching user data:", error);
    }
}

getUserData(1);

In this example, getUserData is an asynchronous function that fetches user data from an API. We use await to wait for the fetch call to resolve and then wait for the response to be converted to JSON. If any error occurs during these operations, it is caught and logged.

Example 2: Sequential Asynchronous Operations

Let's perform multiple asynchronous operations sequentially using async and await:

async function performOperations() {
    try {
        let result1 = await new Promise(resolve => setTimeout(() => resolve("Result 1"), 1000));
        console.log(result1);

        let result2 = await new Promise(resolve => setTimeout(() => resolve("Result 2"), 1000));
        console.log(result2);

        let result3 = await new Promise(resolve => setTimeout(() => resolve("Result 3"), 1000));
        console.log(result3);
    } catch (error) {
        console.error("Error during operations:", error);
    }
}

performOperations();
// Output (each after 1 second): 
// Result 1
// Result 2
// Result 3

In this example, the performOperations function executes three asynchronous operations sequentially, waiting for each to complete before moving to the next. This ensures that the operations are performed in the correct order, and errors are handled gracefully.

The async and await keywords have greatly simplified asynchronous programming in JavaScript. By understanding their differences and how to use them effectively, you can write cleaner, more readable, and more maintainable code. The key takeaway is that async declares a function as asynchronous, returning a promise, while await pauses the execution of an async function until the awaited promise is resolved.

For more detailed information, you can refer to the official MDN documentation on async functions and MDN documentation on await. Happy coding!