Skip to main content

Command Palette

Search for a command to run...

JavaScript Promises Explained for Beginners

Say goodbye to messy code and learn how to handle future values the easy way.

Updated
•4 min read•View as Markdown
JavaScript Promises Explained for Beginners
A

Full-stack developer and startup founder building tech solutions in Ayodhya. Vlogger with 27k+ followers sharing my journey in technology and SaaS.

Have you ever ordered food at a busy fast-food restaurant? You pay for your meal, and the cashier gives you a little buzzer or a receipt with a number.

You don't have your food yet. Instead, you have a promise that you will get your food in the future. You can go sit down, chat with your friends, and wait. When the food is ready, the buzzer goes off, and you get your meal.

In JavaScript, Promises work exactly the same way. A Promise is just an object that represents a value you don't have yet, but will have in the future.

What Problem Do Promises Solve?

To understand why Promises are amazing, we have to look at how things used to be done using Callbacks.

A callback is just a function that you pass into another function to run later. They work fine for simple tasks. But what if you need to do five things in a row, and each step depends on the last one?

With callbacks, you have to put functions inside of functions, inside of functions. This creates a messy "triangle" shape in your code known as Callback Hell (or the Pyramid of Doom). It is very hard to read and fix.

Promises solve this problem. They take deeply nested, messy code and flatten it out into a clean, readable list of steps.

Diagram: Callbacks vs Promises

❌ The Callback Way (Messy & Hard to Read)
getData(function(a) {
    parseData(a, function(b) {
        saveData(b, function(c) {
            console.log("Done!");
        });
    });
});

✅ The Promise Way (Clean & Easy to Read)
getData()
    .then(parseData)
    .then(saveData)
    .then(() => console.log("Done!"));

The 3 States of a Promise

Just like your restaurant order, a JavaScript Promise goes through a lifecycle. At any given moment, a Promise is in one of three states:

  1. Pending: The starting state. The buzzer is sitting on your table. You are waiting for the task to finish.

  2. Fulfilled: Success! The task finished perfectly. Your buzzer is ringing, and your food is ready.

  3. Rejected: Failure. Something went wrong. The restaurant ran out of ingredients, and your order was canceled.

Diagram: Promise Lifecycle

                      +--> FULFILLED (Success)
                     /     
[ PENDING ] --------+      
(Waiting)            \     
                      +--> REJECTED (Error)

Handling Success and Failure

When a Promise finishes, we need a way to grab the result (or handle the error). JavaScript gives us two simple methods to do this: .then() and .catch().

  • .then() runs if the Promise is Fulfilled.

  • .catch() runs if the Promise is Rejected.

Here is what it looks like in action:

// Let's pretend orderFood() returns a Promise
orderFood()
  .then(function(food) {
    // This runs if it succeeds!
    console.log("Yay, time to eat my " + food);
  })
  .catch(function(error) {
    // This runs if it fails!
    console.log("Oh no! " + error);
  });

It reads almost like plain English: Order food, THEN eat it, CATCH any errors.

The Magic of Promise Chaining

The best part about Promises is chaining. Because .then() also returns a new Promise, you can string multiple .then() blocks together.

This is how we fix Callback Hell! Instead of nesting code deeper and deeper to the right, you just add another .then() going straight down.

fetchUserData()
  .then(function(user) {
    return getFriendsList(user.id);
  })
  .then(function(friends) {
    return sendMessage(friends);
  })
  .then(function(successMessage) {
    console.log("Messages sent successfully!");
  })
  .catch(function(error) {
    console.log("Something broke in one of the steps:", error);
  });

Notice how clean that is? If any of the .then() steps fail, JavaScript will skip the rest of the chain and jump straight down to the .catch() block at the very end to handle the error.

Conclusion

Promises might seem confusing at first, but they are just JavaScript's way of handling things that take time. Remember the restaurant buzzer: it starts as Pending, and eventually becomes Fulfilled (handled by .then) or Rejected (handled by .catch).

By using Promises, your code will be flatter, cleaner, and much easier to read!