JavaScript

coding learning websites codepractice

JS Basics

JS Variables & Operators

JS Data Types & Conversion

JS Numbers & Math

JS Strings

JS Dates

JS Arrays

JS Control Flow

JS Loops & Iteration

JS Functions

JS Objects

JS Classes & Modules

JS Async Programming

JS Advanced

JS HTML DOM

JS BOM (Browser Object Model)

JS Web APIs

JS AJAX

JS JSON

JS Graphics & Charts

JavaScript Promises


In JavaScript, asynchronous programming is essential for handling tasks like fetching data from a server, reading files, or waiting for user actions. Originally, this was managed using callbacks, but callbacks often led to complicated, nested code known as callback hell.

To solve this, JavaScript introduced Promises in ES6 (2015). A Promise provides a cleaner, more structured way to work with asynchronous code.

What is a Promise?

A Promise is an object that represents the eventual result of an asynchronous operation. It acts as a placeholder for a value that may not be available immediately but will be resolved at some point in the future.

A Promise has three states:

  • Pending – The initial state, operation not completed yet.

  • Fulfilled – The operation completed successfully.

  • Rejected – The operation failed with an error.

Creating a Promise

A Promise is created using the Promise constructor, which takes a function with two parameters: resolve and reject.

// Creating a promise that resolves or rejects based on a condition
let myPromise = new Promise((resolve, reject) => {
  let success = true; // Simulating a successful operation

  if (success) {
    resolve("Operation successful!"); // Call resolve if the operation succeeded
  } else {
    reject("Operation failed!"); // Call reject if the operation failed
  }
});
  • resolve() is called when the async task completes successfully.

  • reject() is called when something goes wrong.

Consuming a Promise

We use .then() and .catch() to handle the result of a Promise.

// Using the promise
myPromise
  .then(result => {
    console.log("Success:", result); // Runs if promise is fulfilled
  })
  .catch(error => {
    console.log("Error:", error); // Runs if promise is rejected
  });

Example: Simulating Asynchronous Work

// Function that returns a promise simulating data fetching
function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => { // Simulate a delay of 2 seconds
      let dataAvailable = true; // Simulate a condition
      if (dataAvailable) {
        resolve("Data fetched successfully!"); // Resolve promise if data is available
      } else {
        reject("Failed to fetch data."); // Reject promise if data is not available
      }
    }, 2000);
  });
}

// Using the promise
fetchData()
  .then(data => console.log(data)) // Logs success message
  .catch(err => console.log(err)); // Logs error if rejected

Promise Chaining

Promises allow chaining multiple .then() calls to avoid deeply nested callbacks.

fetchData()
  .then(data => {
    console.log(data); // Logs "Data fetched successfully!"
    return "Processing data..."; // Pass value to next then
  })
  .then(processed => {
    console.log(processed); // Logs "Processing data..."
  })
  .catch(err => console.log("Error:", err)); // Catches errors from any previous step

Each .then() receives the return value of the previous one.

Handling Errors

If any part of the Promise chain fails, the error is caught in .catch().

fetchData()
  .then(data => {
    throw new Error("Something went wrong in processing!"); // Simulate an error
  })
  .catch(err => {
    console.error("Caught error:", err.message); // Catch and log the error
  });

finally()

The .finally() method runs whether the Promise is fulfilled or rejected. It’s useful for cleanup tasks.

fetchData()
  .then(data => console.log(data)) // Logs success
  .catch(err => console.log(err)) // Logs error
  .finally(() => console.log("Operation completed")); // Always runs

Promise Combinators

JavaScript provides several utility methods to work with multiple Promises:

// Promise.all runs multiple promises in parallel and waits for all to complete
let p1 = Promise.resolve("One");
let p2 = Promise.resolve("Two");
let p3 = Promise.resolve("Three");

Promise.all([p1, p2, p3])
  .then(results => console.log(results)) // Logs ["One", "Two", "Three"]
  .catch(err => console.log("Error:", err));
// Promise.race returns the result of the first completed promise
let slow = new Promise(resolve => setTimeout(() => resolve("Slow"), 3000));
let fast = new Promise(resolve => setTimeout(() => resolve("Fast"), 1000));

Promise.race([slow, fast])
  .then(result => console.log(result)); // Logs "Fast"
// Promise.allSettled waits for all promises to complete, regardless of success/failure
let p4 = Promise.resolve("Success");
let p5 = Promise.reject("Error");

Promise.allSettled([p4, p5])
  .then(results => console.log(results));
/* Logs:
[
  { status: "fulfilled", value: "Success" },
  { status: "rejected", reason: "Error" }
]
*/
// Promise.any resolves with the first successful promise
let p6 = Promise.reject("Fail 1");
let p7 = Promise.resolve("Success 2");
let p8 = Promise.resolve("Success 3");

Promise.any([p6, p7, p8])
  .then(result => console.log(result)); // Logs "Success 2"

Real-World Example: API Fetch with Promises

// Fetch data from an API
fetch("https://jsonplaceholder.typicode.com/posts/1")
  .then(response => response.json()) // Convert response to JSON
  .then(data => console.log("Fetched Post:", data)) // Log fetched data
  .catch(err => console.error("Fetch error:", err)) // Handle errors
  .finally(() => console.log("Request finished")); // Runs regardless of success/failure

Summary of the Tutorial

  • A Promise is a cleaner way to handle asynchronous operations than callbacks.

  • Promises have three states: pending, fulfilled, rejected.

  • Use .then() for success, .catch() for errors, and .finally() for cleanup.

  • Promise chaining prevents callback hell.

  • Utility methods like Promise.all, Promise.race, Promise.allSettled, and Promise.any help manage multiple async tasks.

Promises form the foundation of modern asynchronous JavaScript, often used with async/await for cleaner syntax and better readability.


Practice Questions

  1. Create a Promise that resolves with "Task completed" after 2 seconds. Use .then() to log the result.

  2. Write a Promise that rejects with "Task failed" if a variable success is false, and resolves if success is true. Handle both cases using .then() and .catch().

  3. Create a function fetchData() that returns a Promise. Inside, simulate a network delay using setTimeout and resolve with "Data fetched". Call the function and log the result.

  4. Chain multiple .then() calls: first resolve a Promise with "Step 1", then return "Step 2", and finally "Step 3". Log each step inside the .then() chain.

  5. Write a Promise that intentionally throws an error inside .then(). Use .catch() to log the error message.

  6. Use .finally() with a Promise that resolves after 1 second. Inside .finally(), log "Cleanup completed" regardless of success or failure.

  7. Create three Promises: p1 resolves after 1 second, p2 after 2 seconds, p3 after 3 seconds. Use Promise.all() to log all results together.

  8. Use Promise.race() with three Promises: one resolves after 1 second, another after 3 seconds, and another after 2 seconds. Log the result of the first resolved Promise.

  9. Create two Promises: one resolves, one rejects. Use Promise.allSettled() to log the status and value/reason of both Promises.

  10. Create a set of Promises where one rejects and others resolve. Use Promise.any() to log the value of the first successfully resolved Promise.


JavaScript

online coding class codepractice

JS Basics

JS Variables & Operators

JS Data Types & Conversion

JS Numbers & Math

JS Strings

JS Dates

JS Arrays

JS Control Flow

JS Loops & Iteration

JS Functions

JS Objects

JS Classes & Modules

JS Async Programming

JS Advanced

JS HTML DOM

JS BOM (Browser Object Model)

JS Web APIs

JS AJAX

JS JSON

JS Graphics & Charts

Go Back Top