Rubypic

Ruby Jane Cabagnot

JavaScript Async Await: A Guide to Asynchronous Programming

In JavaScript, asynchronous programming is a technique used to write efficient and non-blocking code. Async await is a syntax sugar on top of promises that makes it easier to write asynchronous code. In this guide, we’ll explore the ins and outs of async await and its use cases in web development.

Syntax

The syntax for async await is as follows:

const users = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Buby" },
  { id: 3, name: "Charlie" },
];

const articles = [
  { userId: 1, articles: ["Article Alice1", "Article Alice2"] },
  { userId: 2, articles: ["Article Buby3", "Article Buby"] },
  { userId: 3, articles: ["Article Charlie5", "Article Charlie6"] },
];

//the async keyword is used to define an asynchronous function
const example = async () => {
  return "Hello, World!";
};

console.log(example()); // Output: Promise { 'Hello, World!' }

async function someFunc() {
  //the await keyword is used to wait for the promise to resolve
  const result = await example();
  console.log(result); // Output: Hello, World!
  console.log("This will be printed after the promise is resolved"); // Output: This will be printed after the promise is resolved
}

const getData = async () => {
  const user = await getUser("Buby");
  console.log(user); // Output: { id: 2, name: 'Buby' }
};

//another sample of using promise
getUser("Alice")
  .then((user) => getArticles(user.id))
  .then((articles) => console.log(articles))
  .catch((error) => console.log(error));

function getUser(name) {
  return new Promise((resolve, reject) => {
    const user = users.find((user) => user.name === name);

    if (user) {
      resolve(user);
    } else {
      reject(`No user found with the name ${name}`);
    }
  });
}

function getArticles() {
  return new Promise((resolve, reject) => {
    //we are mapping because we want to get the name of the user and articles is an array.
    const userArticles = articles.map((article) => {
      const user = users.find((user) => user.id === article.userId);
      return { name: user.name, articles: article.articles };
    });
    console.log(userArticles); // Output: [ { name: 'Alice', articles: [ 'Article Alice1', 'Article Alice2' ] }, { name: 'Bob', articles: [ 'Article Bob3', 'Article Bob4' ] }, { name: 'Charlie', articles: [ 'Article Charlie5', 'Article Charlie6' ] } ]

    if (user.articles) {
      resolve(userArticles.articles);
    } else {
      reject("Wrong user");
    }
  });
}

Use Cases

Async await is commonly used in web development for the following scenarios:

  1. Fetching Data: When you need to get data from a server, like data from a database or data from another website, it can take a while because it has to send a request to the server, wait for the server to respond, and then send the data back. This can slow down your code and make it harder to understand. Async await can be used to make your code faster and easier to understand. It waits for the server to respond before moving on to the next step of your code. So, it can be used to make API calls to fetch data from a server.
const fetchData = async () => {
  const response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
  const data = await response.json();
  console.log(data);
};

fetchData();

  1. Handling Promises: When working with promises, async await provides a cleaner and more readable syntax for handling asynchronous operations and chaining multiple promises together. For example, when making a request to a server, you would use a promise to handle the response. With async await, you can write code that looks like it is synchronous, but is actually asynchronous. This makes it easier to read and understand the code.
const fetchData1 = async () => {
  try {
    const response1 = await fetch(
      "https://jsonplaceholder.typicode.com/todos/1"
    );
    const data1 = await response1.json();
    console.log(data1);

    const response2 = await fetch(
      "https://jsonplaceholder.typicode.com/todos/2"
    );
    const data2 = await response2.json();
    console.log(data2);
  } catch (error) {
    console.error(error);
  }
};

fetchData1();
  1. Error Handling: Async await simplifies error handling by enabling the use of try-catch blocks. With async await, you can catch and handle errors that may arise during asynchronous operations, making it easier to manage potential errors in your code.
const fetchData2 = async () => {
  try {
    const response = await fetch(
      "https://jsonplaceholder.typicode.com/todos/1"
    );
    if (!response.ok) {
      throw new Error("Failed to fetch data");
    }
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error(error);
  }
};

fetchData2();
  1. Sequential Operations: When using async/await, you can easily perform asynchronous operations one after the other, like a series of steps in a recipe. This makes it easier to manage the flow of your code and ensure that each operation is executed in the correct order. Imagine you’re making a cake, you start by mixing the ingredients, then you pour the batter into the pan, and finally you bake the cake. Each step is an asynchronous operation, and they need to be done in that specific order. With async/await, you can write your code in a way that makes it clear which operations need to happen when, and the code will automatically execute them in the correct sequence.
const fetchData3 = async () => {
  const user = await getUser("Alice");

  const articles = await getArticles(user.id);

  console.log(articles);
};

fetchData3();
  1. Concurrent Operations: Async await also supports concurrent operations by using Promise.all() to run multiple asynchronous tasks concurrently and wait for all of them to complete.
const fetchData4 = async () => {
  const [data1, data2] = await Promise.all([
    fetch("https://jsonplaceholder.typicode.com/todos/1"),
    fetch("https://jsonplaceholder.typicode.com/todos/2"),
  ]);

  const [result1, result2] = await Promise.all([data1.json(), data2.json()]);
  console.log(result1, result2);
};

fetchData4();

By leveraging async await in your JavaScript code, you can write cleaner, more readable, and more maintainable asynchronous code, making it easier to work with asynchronous operations in web development.

Conclusion

In this guide, we’ve explored JavaScript async await and its syntax, use cases, and benefits in web development. Async await is a powerful feature that simplifies asynchronous programming and makes it easier to write and manage asynchronous code. By using async await, you can handle asynchronous operations more effectively, improve code readability, and enhance error handling in your JavaScript applications. Happy coding!