JavaScript Promises: What They Are, How They Work, and Why They Matter

VANSH KANSALVANSH KANSAL
4 min read

What is a Promise?

A Promise is a built-in JavaScript object that represents the eventual completion (or failure) of an asynchronous operation and its resulting value.

In simple words, a Promise is something that promises to do a task and lets you handle what happens after it’s done — whether it was successful or not.


Lets understand with a analogy →

Imagine ordering a pizza online.

  • You place the order.

  • The restaurant gives you a promise that your pizza will be delivered.

  • This promise can be in 3 states:

    1. Pending: Pizza is being prepared.

    2. Fulfilled: Pizza is delivered.

    3. Rejected: Order failed, no pizza for you.

Once the promise is fulfilled or rejected, you act accordingly — enjoy the pizza or order from somewhere else.


🚦 The Three States of a Promise

  1. Pending: The initial state. Task is still running.

  2. Fulfilled: Task completed successfully. You get the result.

  3. Rejected: Task failed. You get an error.


Syntax: How to Create a Promise

const myPromise = new Promise(function(resolve, reject) {
  // async task here
});

What's resolve and reject?

  • resolve(value) → Call this when your async task completes successfully.

  • reject(error) → Call this when something goes wrong.

These are just callback functions passed into your Promise constructor — you control when to call them based on what happens inside the async task.


4 Practical Ways to Create and Use Promises

Example 1: Basic Async Task

const promiseOne = new Promise(function(resolve, reject){
  setTimeout(function(){
    console.log('Async task is complete');
    resolve();
  }, 1000);
});

promiseOne.then(function(){
  console.log("Promise consumed");
});

This prints:

Async task is complete
Promise consumed

Example 2: Shorthand Inline Promise

new Promise(function(resolve, reject){
  setTimeout(function(){
    console.log("Async task 2");
    resolve();
  }, 1000);
}).then(function(){
  console.log("Async 2 resolved");
});

No variable needed if you're chaining immediately.


Example 3: Passing Data via resolve()

const promiseThree = new Promise(function(resolve, reject){
  setTimeout(function(){
    resolve({ username: "Chai", email: "chai@example.com" });
  }, 1000);
});

promiseThree.then(function(user){
  console.log(user); // { username: "Chai", email: "chai@example.com" }
});

Example 4: Handling Errors with .catch()

const promiseFour = new Promise(function(resolve, reject){
  setTimeout(function(){
    let error = true;
    if (!error) {
      resolve({ username: "hitesh", password: "123" });
    } else {
      reject('ERROR: Something went wrong');
    }
  }, 1000);
});

promiseFour
  .then((user) => {
    console.log(user);
    return user.username;
  })
  .then((username) => {
    console.log(username);
  })
  .catch((error) => {
    console.log(error);
  })
  .finally(() => {
    console.log("The promise is either resolved or rejected");
  });

Understanding .then(), .catch(), and .finally()

.then(callback)

Runs when the Promise is fulfilled (i.e., resolved).

promise.then(result => {
  console.log("Got result:", result);
});

.catch(callback)

Runs when the Promise is rejected (i.e., an error occurred).

promise.catch(error => {
  console.log("Caught error:", error);
});

.finally(callback)

Runs no matter what — whether the promise was resolved or rejected.

promise.finally(() => {
  console.log("Cleanup complete!");
});

Useful for hiding loaders, closing modals, etc.


Using Promises with async/await

You can make your code look synchronous using async/await.

const promiseFive = new Promise(function(resolve, reject){
  setTimeout(function(){
    let error = true;
    if (!error) {
      resolve({ username: "javascript", password: "123" });
    } else {
      reject('ERROR: JS went wrong');
    }
  }, 1000);
});

async function consumePromiseFive(){
  try {
    const response = await promiseFive;
    console.log(response);
  } catch (error) {
    console.log(error);
  }
}

consumePromiseFive();

Cleaner, more readable — and highly recommended.


What Does console.log(promise) Show?

It shows the current state of the Promise:

Promise { <pending> }
Promise { <fulfilled>: value }
Promise { <rejected>: reason }

Depending on whether it’s still running, succeeded, or failed.


Bonus: Promise.all()

Want to run multiple async tasks in parallel and wait for all to finish?

Promise.all([promise1, promise2])
  .then((results) => {
    console.log(results); // [result1, result2]
  })
  .catch((error) => {
    console.log("One promise failed:", error);
  });

⚠️ If any one fails, the whole thing rejects.


TL;DR

ConceptDescription
PromiseA placeholder for future value from an async task
Statespending, fulfilled, rejected
resolve()Call when task succeeds
reject()Call when task fails
.then()Runs on success
.catch()Runs on error
.finally()Runs either way (cleanup)
async/awaitMakes promise handling look synchronous

Final Thoughts

Learning promises can feel a bit abstract at first — but once you understand the lifecycle and how to handle success/failure, you’ll unlock the full power of async programming in JavaScript.

Whether you're fetching APIs, handling files, or dealing with database calls — Promises are your async best friend.

10
Subscribe to my newsletter

Read articles from VANSH KANSAL directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

VANSH KANSAL
VANSH KANSAL