Skip to content

Latest commit

 

History

History
129 lines (108 loc) · 4.91 KB

File metadata and controls

129 lines (108 loc) · 4.91 KB

Asynchronous Operations in JavaScript

What is a Promise in JavaScript?

A Promise in JavaScript is an object that represents the eventual completion (or failure) of an asynchronous operation and its resulting value. Promises are a way to handle asynchronous operations more effectively than traditional callback functions, providing a clearer and more manageable approach.

States of a Promise

A Promise can be in one of three states:

  • Pending: The initial state, meaning the operation is still ongoing.
  • Fulfilled: The operation completed successfully, resulting in a resolved value.
  • Rejected: The operation failed, resulting in a reason for the failure (an error).

Creating a Promise

You can create a Promise using the Promise constructor:

let myPromise = new Promise((resolve, reject) => {
  // Simulate an asynchronous operation (like fetching data)
  setTimeout(() => {
    const success = true; // Change to false to see rejection behavior
    if (success) {
      resolve("Operation succeeded!"); // Resolved
    } else {
      reject("Operation failed!"); // Rejected
    }
  }, 3000);
});

Consuming a Promise

You can handle the outcome of a Promise using .then() for success and .catch() for error handling:

myPromise
  .then(result => {
    console.log(result); // success is true: Log "Operation succeeded!" after 3 seconds
  })
  .catch(error => {
    console.log(error); // success is false: Log "Operation failed!" after 3 seconds
  });

Chaining Promises

Promises can be chained to perform multiple asynchronous operations in sequence:

// Simulate success or failure by toggling this variable
const shouldSucceed = true;

function fetchData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (shouldSucceed) {
                resolve("Fetched data"); // Resolve the Promise
            } else {
                reject("Error: Failed to fetch data"); // Reject the Promise
            }
        }, 3000);
    });
}

function processFetchedData(data) {
    return `${data} - Processed`; // Simulate processing of fetched data
}

// Chaining "4" Promises.
fetchData()
    .then(fetchedData => {
        console.log(fetchedData); // Log "Fetched data" after 3 seconds
        return processFetchedData(fetchedData); // Pass data to the next step
    })
    .then(processedData => {
        console.log(processedData); // Log "Fetched data - Processed"
    })
    .catch(error => {
        console.error("Error:", error); // Handle any error in the chain
    });

The final .catch() applies to all preceding .then() calls in the chain. It’s a good way to handle any errors that might arise at any point in the chain without needing to place multiple .catch() statements after each .then().

Why Do We Need async and await?

While Promises greatly improved handling asynchronous code, using them often resulted in chaining multiple .then() calls, which could become unwieldy and harder to read. This is where async and await come into play.

Advantages of async and await

  • Simplicity and Readability: async and await allow you to write asynchronous code that looks and behaves like synchronous code, improving readability.
  • Error Handling: You can use try...catch blocks with async functions to handle errors more gracefully, as opposed to chaining .catch() calls.

Example Using async and await

Here's how you can use async and await with Promises:

// Simulate success or failure by toggling this variable.
const shouldSucceed = true;

function fetchData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (shouldSucceed) {
                resolve("Fetched data"); // Resolve the Promise
            } else {
                reject("Error: Failed to fetch data"); // Reject the Promise
            }
        }, 3000);
    });
}

function processFetchedData(data) {
    return `${data} - Processed`; // Simulate processing of fetched data
}

async function fetchDataAndProcess() {
    try {
        const fetchedData = await fetchData(); // Wait for fetchData to resolve or reject
        console.log(fetchedData); // Log "Fetched data"

        const processedData = processFetchedData(fetchedData);
        console.log(processedData); // Log "Fetched data - Processed"
    } catch (error) {
        console.error("Error:", error); // Handle any error in the try block
    }
}

// Run the async function
fetchDataAndProcess();

Summary

Promises are objects that represent the outcome of asynchronous operations, providing a way to handle results or errors without deep nesting of callbacks.

async and await are syntactic sugar for working with Promises, making asynchronous code easier to read and write. They allow for cleaner error handling and a more synchronous-like flow in asynchronous programming.

This makes it easier to manage complex asynchronous workflows, improving code maintainability and readability.