Async/Await

Async/Await is a modern way to handle asynchronous operations in JavaScript. It is built on top of Promises and provides a cleaner, more readable syntax for writing asynchronous code that looks and behaves like synchronous code.

1. Understanding Async Functions

An async function is a function declared with the async keyword. Inside an async function, you can use the await keyword to pause the execution of the function until a Promise is resolved.

Syntax:

async function functionName() {
  // Code to execute
}

Example:

async function greet() {
  return "Hello, World!";
}

greet().then(message => console.log(message)); // "Hello, World!"

In this example, the greet function is declared as async, and it returns a Promise that resolves to "Hello, World!".

2. The await Keyword

The await keyword can only be used inside an async function. It pauses the execution of the function until the Promise is resolved, returning the resolved value.

Example:

function fetchData() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("Fetched Data");
    }, 2000);
  });
}

async function processData() {
  console.log("Start");
  let data = await fetchData(); // Pauses until fetchData() is resolved
  console.log(data); // "Fetched Data"
  console.log("End");
}

processData();

In this example, await is used to wait for fetchData to resolve before logging the data.

3. Error Handling with Async/Await

You can use try/catch blocks to handle errors in async functions, just like you would in synchronous code.

Example:

async function processData() {
  try {
    let response = await fetch("<https://jsonplaceholder.typicode.com/users/1>");
    if (!response.ok) {
      throw new Error("Network response was not ok");
    }
    let data = await response.json();
    console.log(data);
  } catch (error) {
    console.log("Error: " + error.message);
  }
}

processData();

In this example, the try block contains the code that might throw an error, and the catch block handles any errors that occur.

4. Sequential and Parallel Execution

Async/await makes it easy to write code that runs sequentially. However, you can also run asynchronous operations in parallel for better performance.

Sequential Execution Example:

async function sequentialTasks() {
  let result1 = await task1();
  let result2 = await task2();
  console.log(result1, result2);
}

async function task1() {
  return new Promise(resolve => setTimeout(() => resolve("Task 1 Complete"), 1000));
}

async function task2() {
  return new Promise(resolve => setTimeout(() => resolve("Task 2 Complete"), 2000));
}

sequentialTasks(); // Task 1 Complete, Task 2 Complete

Parallel Execution Example:

async function parallelTasks() {
  let [result1, result2] = await Promise.all([task1(), task2()]);
  console.log(result1, result2);
}

async function task1() {
  return new Promise(resolve => setTimeout(() => resolve("Task 1 Complete"), 1000));
}

async function task2() {
  return new Promise(resolve => setTimeout(() => resolve("Task 2 Complete"), 2000));
}

parallelTasks(); // Task 1 Complete, Task 2 Complete

In the parallel example, Promise.all runs task1 and task2 concurrently, improving performance.

5. Chaining Async Functions

You can chain async functions to create more complex workflows.

Example:

async function step1() {
  return new Promise(resolve => setTimeout(() => resolve("Step 1 Complete"), 1000));
}

async function step2() {
  return new Promise(resolve => setTimeout(() => resolve("Step 2 Complete"), 2000));
}

async function step3() {
  return new Promise(resolve => setTimeout(() => resolve("Step 3 Complete"), 1500));
}

async function executeSteps() {
  try {
    let result1 = await step1();
    console.log(result1);
    let result2 = await step2();
    console.log(result2);
    let result3 = await step3();
    console.log(result3);
  } catch (error) {
    console.log("Error: " + error.message);
  }
}

executeSteps();
// Output:
// Step 1 Complete
// Step 2 Complete
// Step 3 Complete

In this example, each step waits for the previous one to complete before starting the next.

Use Case:

Suppose you're building a web application that needs to fetch user data and display it, but you also want to handle any potential errors gracefully.

HTML:

<!DOCTYPE html>
<html>
  <head>
    <title>Async/Await Example</title>
  </head>
  <body>
    <button id="fetchButton">Fetch User Data</button>
    <div id="output"></div>

    <script src="script.js"></script>
  </body>
</html>

JavaScript (script.js):

document.getElementById("fetchButton").addEventListener("click", async function() {
  try {
    let response = await fetch("https://jsonplaceholder.typicode.com/users/1");
    if (!response.ok) {
      throw new Error("Network response was not ok");
    }
    let user = await response.json();
    document.getElementById("output").innerHTML = `
      <h2>${user.name}</h2>
      <p>Email: ${user.email}</p>
      <p>Phone: ${user.phone}</p>
    `;
  } catch (error) {
    document.getElementById("output").innerHTML = "Error loading user data";
    console.log("Error: " + error.message);
  }
});

In this example:

  • Clicking the button fetches user data from an API asynchronously.

  • The fetched data is displayed in the output div.

  • Errors are handled gracefully with a try/catch block.

This use case demonstrates how to handle asynchronous operations in a web application using async/await, making your code more readable and maintainable. Understanding async/await is essential for modern JavaScript development, allowing you to write cleaner and more efficient asynchronous code.


Help us improve the content 🤩

You can leave comments here.

Last updated