JavaScript Promises Explained — From Callbacks to Clean Code

Understand JavaScript Promises from scratch: creation, chaining, error handling, and how they power modern async code.

JavaScript Beginner 📖 9 min

The Problem with Callbacks

Before Promises, asynchronous JavaScript relied on callbacks, leading to deeply nested code known as "callback hell." Promises provide a cleaner, more maintainable approach.

Creating a Promise

const myPromise = new Promise((resolve, reject) => {
  const success = true;
  if (success) {
    resolve('Operation completed!');
  } else {
    reject(new Error('Something went wrong'));
  }
});

myPromise
  .then(result => console.log(result))
  .catch(error => console.error(error));

Real-World Promise: Fetching Data

function fetchUserData(userId) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (userId > 0) {
        resolve({ id: userId, name: 'John Doe', email: 'john@example.com' });
      } else {
        reject(new Error('Invalid user ID'));
      }
    }, 1000);
  });
}

fetchUserData(1)
  .then(user => {
    console.log('User:', user);
    return fetchUserData(user.id);
  })
  .then(updatedUser => console.log('Updated:', updatedUser))
  .catch(error => console.error('Error:', error.message));

Promise Chaining

Each .then() returns a new Promise, allowing you to chain operations cleanly.

fetch('/api/user')
  .then(response => response.json())
  .then(user => fetch(`/api/posts/${user.id}`))
  .then(response => response.json())
  .then(posts => console.log(posts))
  .catch(error => console.error('Chain failed:', error));

Promise.all — Run in Parallel

const promise1 = fetch('/api/users').then(r => r.json());
const promise2 = fetch('/api/posts').then(r => r.json());
const promise3 = fetch('/api/comments').then(r => r.json());

Promise.all([promise1, promise2, promise3])
  .then(([users, posts, comments]) => {
    console.log({ users, posts, comments });
  })
  .catch(error => {
    console.error('One of the promises failed:', error);
  });

Promise.race — First One Wins

const fastAPI = fetch('/api/fast-endpoint');
const slowAPI = fetch('/api/slow-endpoint');

Promise.race([fastAPI, slowAPI])
  .then(response => {
    console.log('Winner:', response.url);
  });

Promise.any — First Success Wins

Promise.any([
  Promise.reject('Error 1'),
  Promise.reject('Error 2'),
  Promise.resolve('Success!')
]).then(result => {
  console.log(result); // 'Success!'
}).catch(errors => {
  console.log('All failed:', errors);
});

Converting Callbacks to Promises

const { promisify } = require('util');
const fs = require('fs');
const readFileAsync = promisify(fs.readFile);

// Now you can use:
const data = await readFileAsync('file.txt', 'utf8');

Ready to Level Up Your Coding Skills?

Join Coderz Club and learn to code with challenges, battles, and an AI mentor.

Join Coderz Club Free →