Skip to Content
Course content
Click on the "Edit" button in the top corner of the screen to edit your slide content.

I see this mistake constantly when I'm reviewing PRs from junior devs: the assumption that simply calling an asynchronous function inside a .then() block is enough to make the rest of the chain wait for it. It feels intuitive—you're inside a promise chain, so surely the chain knows to wait for the next async task, right?

The "Implicit Wait" Fallacy

Let's look at a concrete example. Imagine we are building a system to process a user's order. We need to verify the user, then check their credit, and finally ship the item. If you write it like this, you've got a problem:

const processOrder = (orderId) => {
  verifyUser(orderId)
    .then(user => {
      // Misconception: I'm calling an async function, so the chain will wait.
      checkCredit(user); 
    })
    .then(() => {
      console.log("Shipping item..."); // This runs IMMEDIATELY
    });
};

Here is why that fails: checkCredit(user) returns a promise, but you aren't doing anything with it. You're just firing it off into the void. Because the first .then() callback doesn't explicitly return that promise, JavaScript assumes the work is done and immediately triggers the next .then() in the chain. Your item ships before the credit check even finishes. In a real production environment, that's how you lose money.

Returning the Promise to Flatten the Chain

To fix this, you have to explicitly return the promise. When you return a promise from a .then() handler, the next .then() in the chain will wait until that specific promise resolves before it executes.

const processOrder = (orderId) => {
  verifyUser(orderId)
    .then(user => {
      // Now we return the promise. The chain "locks" here.
      return checkCredit(user); 
    })
    .then(creditStatus => {
      // This only runs AFTER checkCredit resolves
      console.log(`Credit status: ${creditStatus}. Shipping item...`);
    })
    .catch(err => {
      console.error("Order failed:", err);
    });
};

I like to think of this as "flattening." Without the return, you'd be tempted to nest your promises inside each other (the dreaded "Pyramid of Doom"), which makes the code a nightmare to read. By returning the promise, you keep the chain linear.

What happens if you return a plain value?

You might wonder what happens if you return something that isn't a promise—like a string or a number. JavaScript is actually pretty forgiving here. If you return a non-promise value, the chain wraps that value in a resolved promise automatically. It basically says, "Oh, this is already finished," and passes the value straight to the next .then().

fetchUser(id)
  .then(user => {
    return user.name; // Just a string, not a promise
  })
  .then(name => {
    console.log(`Hello, ${name}`); // Works perfectly
  });

The golden rule I follow is this: if the function you're calling inside .then() returns a promise, you must return that promise if you want the subsequent steps to wait for it. If you don't, you're essentially starting a separate, unmanaged asynchronous process that the rest of your chain knows nothing about.




📋 Practical Task

Implementing a Sequential User Permission Validator

You are building a security gate for a dashboard. You need to create a promise chain that performs three sequential asynchronous checks. If any check fails (rejects), the entire chain should jump to the .catch() block.

Requirements:

  • Start by calling fetchUser(userId).
  • Once the user is fetched, use the result to call verifyEmail(user).
  • Once the email is verified, use that result to call checkAdminPermissions(user).
  • Finally, log "Access Granted" if all three succeed.
  • Ensure you return the promises correctly so the chain executes in order.

Provided Mock Functions:

const fetchUser = (id) => Promise.resolve({ id, name: 'Alex', email: 'alex@example.com' });
const verifyEmail = (user) => Promise.resolve(`Email ${user.email} is verified`);
const checkAdminPermissions = (user) => Promise.resolve('Admin access confirmed');

Write the validateAccess(userId) function to implement this chain.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.