HomeJAVASCRIPTHow to Chain Promises in JavaScript? (Complete Guide)

How to Chain Promises in JavaScript? (Complete Guide)

JavaScript is asynchronous by nature, which means certain operations like API calls, file reads, or database queries don’t block the main thread.
Promises are a powerful way to handle asynchronous tasks in a structured, readable way.

But often, we don’t just want one async taskβ€”we want multiple tasks executed one after another. That’s where Promise chaining comes in.


πŸš€ What is Promise Chaining?

Promise chaining is the technique of executing multiple asynchronous operations in sequence, where each step depends on the result of the previous one.

Instead of writing nested callbacks (callback hell), we can chain .then() handlers.


πŸ“Œ Basic Structure of Promise Chaining

firstPromise()
  .then(result1 => {
    console.log("Step 1:", result1);
    return secondPromise(result1); // pass result to next
  })
  .then(result2 => {
    console.log("Step 2:", result2);
    return thirdPromise(result2);
  })
  .then(result3 => {
    console.log("Step 3:", result3);
  })
  .catch(error => {
    console.error("Error caught:", error);
  });

πŸ›  Example 1: Simple Chaining

function step1() {
  return Promise.resolve("Step 1 completed βœ…");
}

function step2(prev) {
  return Promise.resolve(prev + " β†’ Step 2 completed βœ…");
}

function step3(prev) {
  return Promise.resolve(prev + " β†’ Step 3 completed βœ…");
}

// Chain them
step1()
  .then(result => step2(result))
  .then(result => step3(result))
  .then(finalResult => console.log(finalResult))
  .catch(err => console.error(err));

πŸ‘‰ Output:

Step 1 completed βœ… β†’ Step 2 completed βœ… β†’ Step 3 completed βœ…

πŸ›  Example 2: With Delays (Simulating API calls)

function fakeAPI(name, delay) {
  return new Promise(resolve => {
    setTimeout(() => resolve(`${name} finished after ${delay}ms`), delay);
  });
}

fakeAPI("Task 1", 1000)
  .then(res => {
    console.log(res);
    return fakeAPI("Task 2", 1500);
  })
  .then(res => {
    console.log(res);
    return fakeAPI("Task 3", 500);
  })
  .then(res => console.log(res))
  .catch(err => console.error(err));

πŸ‘‰ Output (with delays):

Task 1 finished after 1000ms
Task 2 finished after 1500ms
Task 3 finished after 500ms

⚑ Execution Flow of Promise Chaining

  1. First async task starts.
  2. When it resolves, its result is passed to the next .then().
  3. If any .then() returns a promise, execution waits for it to finish.
  4. If an error occurs, .catch() is triggered.
  5. Finally, .finally() runs (success or failure).

πŸ›‘ Example 3: Adding Error Handling

function riskyTask() {
  return new Promise((resolve, reject) => {
    const success = Math.random() > 0.5; // random pass/fail
    success ? resolve("Success πŸŽ‰") : reject("Failure ❌");
  });
}

riskyTask()
  .then(res => {
    console.log("Step 1:", res);
    return "Moving to step 2";
  })
  .then(res => {
    console.log("Step 2:", res);
    return riskyTask();
  })
  .then(res => console.log("Step 3:", res))
  .catch(err => console.error("Caught error:", err))
  .finally(() => console.log("Process finished πŸš€"));

πŸ”₯ Advanced: Returning Non-Promise Values

If you return a value (not a promise) inside .then(), it will automatically be wrapped in a resolved promise.

Promise.resolve(10)
  .then(num => num * 2) // returns 20
  .then(num => num + 5) // returns 25
  .then(result => console.log("Final:", result));

πŸ‘‰ Output:

Final: 25

πŸ“Š Promise Chaining vs. async/await

The same process using async/await looks cleaner:

async function processTasks() {
  try {
    const res1 = await fakeAPI("Task 1", 1000);
    console.log(res1);

    const res2 = await fakeAPI("Task 2", 1500);
    console.log(res2);

    const res3 = await fakeAPI("Task 3", 500);
    console.log(res3);
  } catch (err) {
    console.error("Error:", err);
  } finally {
    console.log("All tasks done πŸš€");
  }
}

processTasks();

βœ… FAQs on Promise Chaining

Q1. Do promises run in parallel or sequential in chaining?
πŸ‘‰ In chaining, they run sequentially, one after another. For parallel, use Promise.all().

Q2. What happens if I forget to return in .then()?
πŸ‘‰ The next .then() won’t receive the previous result (undefined will be passed).

Q3. Can I mix synchronous and asynchronous code in chaining?
πŸ‘‰ Yes, any return value will be wrapped in a promise automatically.

Q4. Difference between .then().catch() vs try...catch?
πŸ‘‰ .then().catch() is promise-style, while try...catch works with async/await.

Q5. Is .finally() always executed?
πŸ‘‰ Yes, whether success or failure, .finally() always runs.


🎯 Key Takeaways

For cleaner syntax β†’ prefer async/await.’d use Promise.all() instead of chaining .then().

Promise chaining avoids callback hell.

Always return inside .then() to pass results forward.

Use .catch() for centralized error handling.

Use .finally() for cleanup (like closing DB connections).

Share:Β 

No comments yet! You be the first to comment.

Leave a Reply

Your email address will not be published. Required fields are marked *