A brief info in way of handling Asynchronous in Js


Topics covered Promises and its methods, Async, Await, Web-API.

Introduction

In real-world JavaScript, we use async, await, and promises to deal with tasks that take time, like fetching data or handling user interactions. Promises help organize and make our code cleaner for these tasks. Async/await makes it even simpler, making the code look like it runs step by step, even though it's doing multiple things at once. It's like cooking a meal - you can start boiling water, chop veggies, and simmer sauce simultaneously, making the process faster and more efficient. In short, async and promises make our code handle multiple jobs smoothly, providing a better experience for users interacting with web applications.

Understanding Promises

Promises represent the eventual completion or failure of an asynchronous operation and its resulting value. They help streamline the flow of asynchronous code, making it more readable and maintainable.

Lets, code on Promises

function hero() {
  return new Promise((resolve, reject) => {
    if (100 % 2 == 0) {
      resolve("Yay, We got it")
    } else {
      reject("Unfortunately, we didn't make it happen")
    }
  })
}

hero().then((data) => {
    console.log(`data  ${data}`)
  })
  .catch((error) => {
    console.log(` error occured   ${error}`)
  })  

// output - " data  Yay, We got it"


// if it the statment(condition) provided is false,
// then output wiil be -
// " error occured   Unfortunately, we didn't make it happen"

Let's break the code in simpler way.

The hero function returns a promise that resolves with "Yay, We got it" if 100 is divisible by 2 (which is true), and rejects with "Unfortunately, we didn't make it happen" otherwise. When calling hero().then(), the promise resolves, and the success callback prints "data Yay, We got it" to the console. If the statement were false, it would print "error occurred Unfortunately, we didn't make it happen" due to the catch block capturing the rejection.

Let's get deeper into the promises methods.

Key Promise Methods

Promise.resolve

Promise.resolve returns a resolved promise with a given value. It's useful when you want to create a promise that is immediately resolved.

const resolvedPromise = Promise.resolve("Resolved value");
resolvedPromise.then(result => console.log(result)); // Output: Resolved value

Promise.reject

Promise.reject returns a rejected promise with a given reason. It's handy for creating a promise that is immediately rejected.

const rejectedPromise = Promise.reject("Error reason");
rejectedPromise.catch(error => console.error(error)); // Output: Error reason

Promise.all

Promise.all takes an array of promises and returns a single promise that resolves when all the promises in the array resolve. If any promise in the array is rejected, the entire Promise.all is rejected.

const promise1 = Promise.resolve("Promise 1");
const promise2 = Promise.resolve("Promise 2");

Promise.all([promise1, promise2])
  .then(results => console.log(results)) // Output: ["Promise 1", "Promise 2"]
  .catch(error => console.error(error));
// if error it only return on the error one

Promise.allSettled

Promise.allSettled is similar toPromise.all, but it waits for all promises to settle, whether resolved or rejected. It returns an array of objects representing the outcome of each promise.

const promise1 = Promise.resolve("Resolved Promise");
const promise2 = Promise.reject("Rejected Promise");

Promise.allSettled([promise1, promise2])
  .then(results => console.log(results))
  // Output: [{status: "fulfilled", value: "Resolved Promise"},
  //          {status: "rejected", reason: "Rejected Promise"}]
  .catch(error => console.error(error));

Promise.any

Promise.any returns the first promise in an iterable that fulfills, not waiting for all promises to settle. If all promises are rejected, it returns an aggregate rejection.

const promise1 = Promise.reject("Promise 1 rejected");
const promise2 = Promise.resolve("Promise 2 resolved");

Promise.any([promise1, promise2])
  .then(result => console.log(result)) // Output: Promise 2 resolved
  .catch(errors => console.error(errors));

Promise.race

Promise.race returns a promise that fulfills or rejects as soon as one of the promises in an iterable fulfills or rejects.

const promise1 = new Promise(resolve => setTimeout(() => resolve("Promise 1"), 1000));
const promise2 = new Promise(resolve => setTimeout(() => resolve("Promise 2"), 500));

Promise.race([promise1, promise2])
  .then(result => console.log(result)) // Output: Promise 2
  .catch(error => console.error(error));

Now, Let's go to async

Async

In JavaScript, async is a keyword used before a function declaration to indicate that the function will handle asynchronous operations. It allows the use of await inside the function, making it possible to pause execution until a Promise is resolved.

Await

The await keyword is used within functions declared with async. It tells JavaScript to wait for the resolution of a Promise before moving on to the next line of code. This makes asynchronous code look and behave more like synchronous code, improving readability and maintainability.

Code

async function hero(){
    async function delay(number) {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log("Hero is back!");
      resolve("Heroine, I am coming");
    }, number * 1000);
  });
}

async function hero() {
  let answer = await delay(1);
  console.log(answer);
}

hero();
}

Certainly! Let's break down the code in a simpler way:

  1. delay Function:

    • The delay function takes a parameter number, which represents the number of seconds to wait.

    • Inside the delay function, a Promise is created. This promise will resolve after the specified delay using setTimeout.

    • The setTimeout function is used to wait for a certain amount of time (given by number * 1000 milliseconds).

    • When the timeout is reached, it logs "Hero is back!" to the console and resolves the promise with the message "Heroine, I am coming."

  2. hero Function:

    • Inside the hero function, it uses the await keyword to pause the execution and wait for the delay function to complete.

    • Specifically, it awaits the result of calling delay(1), meaning it waits for 1 second (as specified in the argument).

    • Once the delay is over, it continues the execution, and the result of the delay function (in this case, "Heroine, I am coming") is stored in the variable answer.

    • Finally, it logs the value of answer to the console.

  3. Calling the hero Function:

    • The hero function is called at the end of the code.

    • When you run the script, it triggers the hero function, and you'll see the messages logged to the console after the specified delay.

In summary, this code simulates a situation where a hero is taking some time to come back, and the hero function logs a message indicating that the hero is back after a delay of 1 second.

Understanding Web APIs:

Web APIs serve as intermediaries that enable the interaction between different software systems. They provide a set of rules and protocols for building and interacting with web services, allowing developers to access and manipulate data from remote servers. These APIs can be used for various purposes, such as retrieving data from a database, integrating with third-party services, or even creating your own services for others to consume.

  • HTTP Requests:

    • Web APIs communicate using the HTTP protocol, primarily through two types of requests: GET and POST. GET requests retrieve data, while POST requests submit data to the server.
  • Fetch API:

    • The Fetch API is a modern JavaScript interface for making network requests. It provides a cleaner and more powerful alternative to the older XMLHttpRequest.
  •   fetch('https://api.example.com/data')
            .then(response => response.json())
            .then(data => console.log(data))
            .catch(error => console.error('Error:', error));
    
  • Asynchronous JavaScript (Async/Await):

    • Asynchronous programming is crucial when working with Web APIs to prevent blocking the main thread. Async/await is a syntax for handling promises more comfortably.
  •   async function fetchData() {
            try {
            const response = await fetch('https://api.example.com/data');
            const data = await response.json();
            console.log(data);
            }
            catch (error) {
                console.error('Error:', error);
            }}
    
            fetchData();
    
  • Handling API Responses:

    • Proper handling of API responses is essential. It involves checking for errors, parsing data, and updating the UI accordingly.

    •         // Simulating a web API request function
        function fetchDataFromAPI() {
              const apiUrl = 'https://jsonplaceholder.typicode.com/todos/1';
      
              return new Promise((resolve, reject) => {
                  // Simulating an asynchronous operation, like fetching data from an API
              fetch(apiUrl)
              .then(response => {
                      if (!response.ok) {
                        throw new Error(`HTTP error! Status: ${response.status}`);
                      }
                      return response.json();
                    })
                    .then(data => resolve(data))
                    .catch(error => reject(error));
                });
              }
      
              // Async function using async/await
              async function getData() {
                try {
                  const result = await fetchDataFromAPI();
                  console.log(result);
                } catch (error) {
                  console.error(error);
                }
              }
      
              // Using Promises directly
              fetchDataFromAPI()
                .then(result => console.log(result))
                .catch(error => console.error(error));
      
              // Calling the async function
              getData();
      

In this example, we are fetching data from the JSONPlaceholder API using the fetch function. The fetchDataFromAPI function returns a Promise that resolves with the fetched data or rejects with an error message. The getData function demonstrates the use of async/await, and the fetchDataFromAPI().then().catch() structure shows the use of Promises directly.

Conclusion

Till now, we explored the foundational concept of Promises and their methods, providing a robust tool for managing asynchronous operations in JavaScript. Delving into the powerful combination of async/await enhanced code readability and synchronous-like structure. We also harnessed the capabilities of Web APIs to interact with external resources seamlessly. This journey through Promises, async/await, and Web APIs equips developers with the essential tools to write efficient and organized asynchronous JavaScript code.