Skip to main content

Command Palette

Search for a command to run...

JavaScript Promises Explained for Beginners

Understanding async code without getting lost in callbacks

Updated
•3 min read•View as Markdown

Introduction

When I first started working with asynchronous JavaScript, callbacks felt manageable… until they didn’t.

One function inside another, inside another — suddenly the code becomes hard to read, debug and maintain.

That’s exactly where Promises come in.

Let’s break it down in the simplest way possible.


The Problem Promises Solve

Before promises, we used callbacks to handle async operation.

getUser(function(user) {
  getOrders(user.id, function(orders) {
    getDetails(orders, function(details) {
      console.log(details);
    });
  });
});

This is often called callback hell.

Problems here:

  • Hard to read

  • Difficult to handle errors

  • Not scalable

Promises solve this by giving structure to async code.


What is a Promise?

Think of a promise as a value that will be available in the future.

Just like,

  • You order food --> it’s not ready yet

  • After some time --> it’s delivered

In JavaScript:

  • The result is not immediate

  • But you are promised a result late


Promise States

A promise can be in one of three states:

  1. Pending

    • Initial state

    • Work is still going on

  2. Fulfilled

    • Operation completed successfully

    • You get the result

  3. Rejected

    • Operation failed

    • You get an error

A promise can only move forward.

Pending → Fulfilled Pending → Rejected

Once settled, it cannot change.


Basic Promise Lifecycle

Here's how a promise is created

const myPromise = new Promise((resolve, reject) => {
  let success = true;

  if (success) {
    resolve("Task completed");
  } else {
    reject("Something went wrong");
  }
});

Breaking it down:

  • resolve() → success

  • reject() → failure


Handling Success and Failure

We use .then() and .catch() to handle results.

myPromise
  .then((result) => {
    console.log(result); // success
  })
  .catch((error) => {
    console.log(error); // failure
  });

Clean and readable compared to callbacks.


Promise Chaining Concept

One of the biggest advantages of promises is chaining.

fetchData()
  .then((data) => {
    return processData(data);
  })
  .then((processed) => {
    return saveData(processed);
  })
  .then((result) => {
    console.log("Final result:", result);
  })
  .catch((error) => {
    console.log("Error:", error);
  });

Why this is powerful:

  • Avoids nested callbacks

  • Keeps flow linear

  • Easier error handling (single .catch())


Promises vs Callbacks

Feature Callbacks Promises
Readability Poor (nested) Clean (chainable)
Error Handling Difficult Centralized
Scalability Hard Easy
Flow Control Messy Structured

Real-Life Example (API Call)

fetch("https://api.example.com/data")
  .then((response) => response.json())
  .then((data) => {
    console.log(data);
  })
  .catch((error) => {
    console.log("Error fetching data:", error);
  });

This is how modern apps handle data from servers.

1 views