Falytom logoFALYTOM
Games
ToolsUI ComponentsServicesProductsAbout
LoginSign Up
menu
  1. Home
  2. /Web Development
  3. /Javascript
  4. /Promises
Your Progress0%
0 of 61 completed

JavaScript Topics

Getting Started

  • What is JavaScript?
  • JavaScript vs Other Languages
  • Setting Up Your JavaScript Environment
  • Developer Console and Debugging Basics

JavaScript Fundamentals

  • Variables (var, let, const)
  • Data Types and Type Checking
  • Comments and Code Organization
  • String Methods and Template Literals
  • Type Conversion and Coercion
  • Operators (Arithmetic, Comparison, Logical)

Control Flow

  • If/Else Statements
  • Switch Statements
  • Ternary Operator
  • Truthy and Falsy Values
  • Logical Operators and Short-Circuiting

Loops and Iteration

  • For Loops
  • While and Do-While Loops
  • For...of and For...in Loops
  • Break and Continue Statements

Functions

  • Function Declarations and Expressions
  • Arrow Functions
  • Function Parameters and Arguments
  • Return Statements and Values
  • Scope and Closures
  • Higher-Order Functions and Callbacks

Arrays

  • Array Basics and Creation
  • Array Methods: Adding and Removing Elements
  • Array Iteration Methods (forEach, map, filter)
  • Array Methods: find, some, every, reduce
  • Sorting, Reversing, and Array Transformation

Objects

  • Object Basics and Properties
  • Object Methods and 'this' Keyword
  • Object Destructuring
  • Object.keys, values, entries
  • Spread Operator and Object Cloning

DOM Manipulation

  • Introduction to the DOM
  • Selecting Elements (querySelector, getElementById)
  • Modifying Elements (textContent, innerHTML, style)
  • Creating and Removing Elements
  • Event Listeners and Event Handling
  • Event Object and Event Delegation

Asynchronous JavaScript

  • Understanding Asynchronous Code
  • setTimeout and setInterval
  • Callbacks and Callback Hell
  • Promises and Promise Chaining
  • Async/Await

Error Handling

  • Try, Catch, Finally
  • Throwing Custom Errors

Modern JavaScript Features

  • ES6+ Overview
  • Modules (import/export)
  • Optional Chaining and Nullish Coalescing
  • Rest and Spread Operators

Working with Data

  • JSON (Parse and Stringify)
  • Fetch API and HTTP Requests
  • Working with Local Storage

Advanced Concepts

  • Classes and Object-Oriented Programming
  • Array and Object Advanced Patterns
  • Regular Expressions Basics

Best Practices & Real-World Application

  • JavaScript Best Practices
  • Debugging Techniques and Tools
  • Building a Complete Interactive Project

Promises and Promise Chaining

Modern asynchronous code without callback hell

Promises revolutionized asynchronous JavaScript by providing a cleaner, more manageable alternative to callbacks. A Promise represents a value that may be available now, in the future, or never. With Promises, you can write flat, readable async code using .then() and .catch(), chain operations elegantly, and handle errors consistently. Understanding Promises is essential for modern JavaScript development—they're the foundation of async/await and are used throughout modern APIs. Let's master Promises!

What Are Promises?

A Promise is an object representing the eventual completion or failure of an asynchronous operation.

Promise Analogy:

Think of a promise like ordering food at a restaurant. When you order, you get a receipt (the promise). The receipt isn't your food—it's a promise that you'll eventually get your food. While waiting, you can do other things. Eventually, you either get your food (fulfilled) or get a refund because they're out (rejected).

Promise States

TEXT
A Promise is always in one of three states:

1. Pending (Initial State)
   - Operation hasn't completed yet
   - Promise is still working

2. Fulfilled (Success)
   - Operation completed successfully
   - Promise has a resulting value
   - Also called "resolved"

3. Rejected (Failure)
   - Operation failed
   - Promise has a reason for failure (error)

State Transitions:
Pending → Fulfilled (success)
Pending → Rejected (failure)

Once fulfilled or rejected, a promise is "settled"
and can never change state again.

Creating Promises

Basic Promise Creation

JAVASCRIPT
// Create a Promise with the Promise constructor
let promise = new Promise(function(resolve, reject) {
  // Executor function runs immediately
  
  // Simulate async operation
  let success = true;
  
  if (success) {
    resolve('Operation successful!');  // Fulfill the promise
  } else {
    reject('Operation failed!');  // Reject the promise
  }
});

console.log(promise);  // Promise { <pending> } initially

// resolve() - call when operation succeeds
// reject() - call when operation fails

// Example: Delayed resolution
let delayedPromise = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve('Completed after 2 seconds');
  }, 2000);
});

console.log(delayedPromise);  // Promise { <pending> }
// After 2 seconds: Promise { 'Completed after 2 seconds' }

Promise with Async Operation

JAVASCRIPT
// Simulating async file read
function readFilePromise(filename) {
  return new Promise(function(resolve, reject) {
    console.log('Reading file:', filename);
    
    // Simulate async file read
    setTimeout(function() {
      if (filename === 'data.txt') {
        resolve('File contents here');
      } else {
        reject(new Error('File not found'));
      }
    }, 1000);
  });
}

let promise = readFilePromise('data.txt');
console.log(promise);  // Promise { <pending> }

// Simulating database query
function queryDatabase(query) {
  return new Promise((resolve, reject) => {
    console.log('Executing query:', query);
    
    setTimeout(() => {
      if (query.includes('SELECT')) {
        resolve([
          { id: 1, name: 'Alice' },
          { id: 2, name: 'Bob' }
        ]);
      } else {
        reject(new Error('Invalid query'));
      }
    }, 1500);
  });
}

Consuming Promises

then() - Handling Success

JAVASCRIPT
let promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('Success!');
  }, 1000);
});

// Handle success with .then()
promise.then(function(result) {
  console.log('Promise fulfilled:', result);
});

// Output (after 1 second):
// Promise fulfilled: Success!

// Arrow function syntax (more common)
promise.then(result => {
  console.log('Result:', result);
});

// You can attach multiple .then() handlers
promise.then(result => console.log('Handler 1:', result));
promise.then(result => console.log('Handler 2:', result));
// Both execute when promise resolves

// Practical example
function fetchUser(userId) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ id: userId, name: 'Alice', email: 'alice@test.com' });
    }, 1000);
  });
}

fetchUser(1).then(user => {
  console.log('User loaded:', user.name);
  console.log('Email:', user.email);
});

catch() - Handling Errors

JAVASCRIPT
let promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(new Error('Something went wrong!'));
  }, 1000);
});

// Handle error with .catch()
promise.catch(function(error) {
  console.log('Promise rejected:', error.message);
});

// Output (after 1 second):
// Promise rejected: Something went wrong!

// Arrow function
promise.catch(error => {
  console.log('Error:', error.message);
});

// Practical example
function fetchUser(userId) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (userId > 0) {
        resolve({ id: userId, name: 'Alice' });
      } else {
        reject(new Error('Invalid user ID'));
      }
    }, 1000);
  });
}

fetchUser(-1).catch(error => {
  console.log('Failed to fetch user:', error.message);
});

// Using both then and catch
fetchUser(1)
  .then(user => {
    console.log('Success:', user.name);
  })
  .catch(error => {
    console.log('Error:', error.message);
  });

finally() - Always Executes

JAVASCRIPT
// finally() runs regardless of success or failure
function fetchData() {
  return new Promise((resolve, reject) => {
    let random = Math.random();
    
    setTimeout(() => {
      if (random > 0.5) {
        resolve('Data loaded');
      } else {
        reject(new Error('Failed to load'));
      }
    }, 1000);
  });
}

fetchData()
  .then(result => {
    console.log('Success:', result);
  })
  .catch(error => {
    console.log('Error:', error.message);
  })
  .finally(() => {
    console.log('Cleanup: Hide loading spinner');
    // Runs regardless of success or failure
    // Perfect for cleanup operations
  });

// Practical use case
function loadUserData(userId) {
  showLoadingSpinner();  // Show loading
  
  return fetchUser(userId)
    .then(user => {
      displayUser(user);
    })
    .catch(error => {
      showError(error.message);
    })
    .finally(() => {
      hideLoadingSpinner();  // Always hide loading
    });
}

Promise Chaining

The real power of Promises: chain async operations in a flat, readable structure.

Basic Chaining

JAVASCRIPT
// .then() returns a new Promise
// This allows chaining

Promise.resolve(5)
  .then(value => {
    console.log('Value:', value);  // 5
    return value * 2;  // Return value for next .then()
  })
  .then(value => {
    console.log('Doubled:', value);  // 10
    return value + 3;
  })
  .then(value => {
    console.log('Final:', value);  // 13
  });

// Output:
// Value: 5
// Doubled: 10
// Final: 13

// Each .then() receives the return value of the previous .then()

Chaining Async Operations

JAVASCRIPT
// Sequential async operations (no callback hell!)
function getUser(userId) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({ id: userId, name: 'Alice' });
    }, 1000);
  });
}

function getPosts(userId) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve([
        { id: 1, title: 'Post 1' },
        { id: 2, title: 'Post 2' }
      ]);
    }, 1000);
  });
}

function getComments(postId) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve([
        { id: 1, text: 'Great post!' },
        { id: 2, text: 'Thanks!' }
      ]);
    }, 1000);
  });
}

// Chain them together (flat structure!)
getUser(1)
  .then(user => {
    console.log('User:', user.name);
    return getPosts(user.id);  // Return promise
  })
  .then(posts => {
    console.log('Posts:', posts.length);
    return getComments(posts[0].id);  // Return promise
  })
  .then(comments => {
    console.log('Comments:', comments.length);
  })
  .catch(error => {
    console.log('Error:', error.message);
  });

// Output (each after 1 second):
// User: Alice
// Posts: 2
// Comments: 2

// No nesting! Flat and readable!

Promises flatten async code

Callback Hell

// Callbacks (nested hell)
getUser(1, function(err, user) {
  if (err) return handleError(err);
  
  getPosts(user.id, function(err, posts) {
    if (err) return handleError(err);
    
    getComments(posts[0].id, function(err, comments) {
      if (err) return handleError(err);
      
      console.log('Done!', comments);
    });
  });
});

// Deeply nested
// Hard to read
// Repetitive error handling
Output:
Not run yet...

Promise Chain

// Promises (flat chain)
getUser(1)
  .then(user => getPosts(user.id))
  .then(posts => getComments(posts[0].id))
  .then(comments => {
    console.log('Done!', comments);
  })
  .catch(handleError);

// Flat structure
// Easy to read
// Single error handler
// Much better!
Output:
Not run yet...

Error Handling in Promises

Catch Handles All Errors

JAVASCRIPT
// .catch() handles errors from any previous .then()
getUser(1)
  .then(user => {
    console.log('User:', user.name);
    return getPosts(user.id);
  })
  .then(posts => {
    throw new Error('Something went wrong!');  // Error!
    return getComments(posts[0].id);
  })
  .then(comments => {
    console.log('This will not run');
  })
  .catch(error => {
    console.log('Caught error:', error.message);
    // Catches errors from any step above
  });

// Output:
// User: Alice
// Caught error: Something went wrong!

// .catch() is like a try-catch for the entire chain

Error Recovery

JAVASCRIPT
// .then() after .catch() continues the chain
fetchPrimaryData()
  .catch(error => {
    console.log('Primary failed, trying backup');
    return fetchBackupData();  // Try backup
  })
  .then(data => {
    console.log('Data loaded:', data);
    // This runs whether primary or backup succeeded
  })
  .catch(error => {
    console.log('Both failed:', error.message);
  });

// Multiple catch handlers
step1()
  .then(result => step2(result))
  .catch(error => {
    console.log('Step 1 or 2 failed:', error.message);
    return 'default value';  // Recover with default
  })
  .then(result => step3(result))
  .catch(error => {
    console.log('Step 3 failed:', error.message);
  });

Best Practices

JAVASCRIPT
// ✓ Good: Always end chain with .catch()
fetchData()
  .then(processData)
  .then(saveData)
  .catch(handleError);  // Catches all errors

// ✗ Bad: No error handling (unhandled rejection)
fetchData()
  .then(processData)
  .then(saveData);
// If error occurs, it's unhandled!

// ✓ Good: Specific error handling + general catch
fetchData()
  .then(data => {
    if (!data) {
      throw new Error('No data received');
    }
    return processData(data);
  })
  .catch(error => {
    if (error.message === 'No data received') {
      return getDefaultData();  // Specific recovery
    }
    throw error;  // Re-throw other errors
  })
  .then(saveData)
  .catch(handleError);  // General error handler

Promise Static Methods

Promise.all() - All or Nothing

JAVASCRIPT
// Wait for ALL promises to resolve
let promise1 = Promise.resolve(3);
let promise2 = new Promise(resolve => setTimeout(() => resolve(42), 1000));
let promise3 = Promise.resolve('foo');

Promise.all([promise1, promise2, promise3])
  .then(results => {
    console.log('All resolved:', results);
    // [3, 42, 'foo']
  });

// If ANY promise rejects, entire Promise.all rejects
let p1 = Promise.resolve(1);
let p2 = Promise.reject(new Error('Failed!'));
let p3 = Promise.resolve(3);

Promise.all([p1, p2, p3])
  .then(results => {
    console.log('Success:', results);
  })
  .catch(error => {
    console.log('Failed:', error.message);
    // "Failed!" - stops at first rejection
  });

// Practical: Load multiple resources
Promise.all([
  fetchUser(1),
  fetchPosts(1),
  fetchComments(1)
])
  .then(([user, posts, comments]) => {
    console.log('All loaded:', user, posts, comments);
  })
  .catch(error => {
    console.log('At least one failed:', error.message);
  });

Promise.race() - First to Finish

JAVASCRIPT
// Returns result of FIRST promise to settle
let slow = new Promise(resolve => setTimeout(() => resolve('slow'), 2000));
let fast = new Promise(resolve => setTimeout(() => resolve('fast'), 1000));

Promise.race([slow, fast])
  .then(result => {
    console.log('Winner:', result);  // "fast"
  });

// Practical: Timeout for slow operations
function fetchWithTimeout(url, timeout = 5000) {
  let fetchPromise = fetch(url);
  
  let timeoutPromise = new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(new Error('Request timeout'));
    }, timeout);
  });
  
  return Promise.race([fetchPromise, timeoutPromise]);
}

fetchWithTimeout('/api/data', 3000)
  .then(response => console.log('Got response'))
  .catch(error => console.log('Timeout or error:', error.message));

Promise.allSettled() - Wait for All (Regardless of Result)

JAVASCRIPT
// Wait for ALL promises to settle (resolve or reject)
let p1 = Promise.resolve(1);
let p2 = Promise.reject(new Error('Failed'));
let p3 = Promise.resolve(3);

Promise.allSettled([p1, p2, p3])
  .then(results => {
    console.log(results);
    // [
    //   { status: 'fulfilled', value: 1 },
    //   { status: 'rejected', reason: Error: Failed },
    //   { status: 'fulfilled', value: 3 }
    // ]
    
    results.forEach((result, index) => {
      if (result.status === 'fulfilled') {
        console.log(`Promise ${index} succeeded:`, result.value);
      } else {
        console.log(`Promise ${index} failed:`, result.reason.message);
      }
    });
  });

// Useful when you want results from all promises,
// even if some fail

Promise.any() - First Success

JAVASCRIPT
// Returns first SUCCESSFUL promise
let p1 = Promise.reject(new Error('Error 1'));
let p2 = new Promise(resolve => setTimeout(() => resolve('Success!'), 1000));
let p3 = Promise.reject(new Error('Error 3'));

Promise.any([p1, p2, p3])
  .then(result => {
    console.log('First success:', result);  // "Success!"
  })
  .catch(error => {
    console.log('All failed');
  });

// Practical: Try multiple servers
Promise.any([
  fetch('https://api1.example.com/data'),
  fetch('https://api2.example.com/data'),
  fetch('https://api3.example.com/data')
])
  .then(response => console.log('Got response from fastest working server'))
  .catch(error => console.log('All servers failed'));

Practical Examples

Example 1: User Registration Flow

JAVASCRIPT
// Clean async flow with Promises (vs callback hell)
function registerUser(userData) {
  return validateUserData(userData)
    .then(validData => {
      return checkEmailExists(validData.email)
        .then(exists => {
          if (exists) {
            throw new Error('Email already registered');
          }
          return validData;
        });
    })
    .then(validData => hashPassword(validData.password))
    .then(hashedPassword => {
      return saveToDatabase({
        ...userData,
        password: hashedPassword
      });
    })
    .then(user => {
      // Send email but don't wait for it
      sendWelcomeEmail(user.email).catch(err => {
        console.log('Email warning:', err);
      });
      return user;
    })
    .then(user => createSession(user.id))
    .then(session => {
      return { user: session.user, session };
    });
}

// Usage
registerUser({
  email: 'alice@test.com',
  password: 'secret123',
  name: 'Alice'
})
  .then(result => {
    console.log('Registration successful!', result.user.name);
  })
  .catch(error => {
    console.log('Registration failed:', error.message);
  });

Example 2: Sequential Data Processing

JAVASCRIPT
// Process data in sequence
function processUserData(userId) {
  let userData = {};
  
  return fetchUser(userId)
    .then(user => {
      userData.user = user;
      console.log('✓ User fetched:', user.name);
      return fetchPosts(user.id);
    })
    .then(posts => {
      userData.posts = posts;
      console.log('✓ Posts fetched:', posts.length);
      
      // Process all posts in parallel
      let commentPromises = posts.map(post => fetchComments(post.id));
      return Promise.all(commentPromises);
    })
    .then(commentsArray => {
      userData.comments = commentsArray.flat();
      console.log('✓ Comments fetched:', userData.comments.length);
      return userData;
    })
    .catch(error => {
      console.log('✗ Error:', error.message);
      throw error;
    });
}

processUserData(1)
  .then(data => {
    console.log('All data loaded:', data);
  })
  .catch(error => {
    console.log('Failed to load data');
  });

Promises and Promise Chaining

Master modern async JavaScript

Output:
Click "Run" to execute your code...
💡 Tip: Use console.log() to see your output in the console above.

Key Takeaways

  • Promise: object representing eventual completion/failure of async operation
  • Three states: pending, fulfilled, rejected
  • new Promise((resolve, reject) => ...) creates promise
  • .then() handles success, .catch() handles errors
  • .finally() runs regardless of outcome (cleanup)
  • Promise chaining: flat, readable sequential async operations
  • Return promises from .then() to chain them
  • Promise.all() waits for all promises
  • Promise.race() returns first to settle
  • Always end chains with .catch() for error handling

What's Next?

You now understand Promises—the modern solution to callback hell! You've learned to create promises, handle success and errors, chain operations elegantly, and use powerful methods like Promise.all() and Promise.race().

In the final async lesson, we'll explore Async/Await—syntactic sugar that makes Promises even cleaner! Async/await allows you to write asynchronous code that looks synchronous, making it incredibly readable and maintainable. It's the pinnacle of async JavaScript!

💪 Practice Challenge:

Before moving on, try creating:

  1. A promise that resolves after a delay with a value
  2. Chain three async operations using .then()
  3. Use Promise.all() to load multiple resources in parallel
  4. Implement proper error handling with .catch()
  5. Convert callback-based code to promise-based code

Test Your Understanding

Question 1 / 4

What is a Promise in JavaScript?

Score: 0 / 0

Mastering JavaScript Promises! 🎯

Previous
Callbacks and Callback Hell
Next
Async/Await

Continue Learning JavaScript

Join 2,000+ developers mastering JavaScript async programming. New lessons weekly - 100% FREE.

You might also like

UI Components

Ready-made components for your projects

Developer Tools

Boost productivity with handy generators

HTML Game

Learn HTML concepts through interactive gameplay

Join Our Web Development Training Program

Master frontend & backend development with hands-on projects.

JavaScript Tutorials

0 of 61 completed

Your Progress0%

Topics

Getting Started

  • What is JavaScript?
  • JavaScript vs Other Languages
  • Setting Up Your JavaScript Environment
  • Developer Console and Debugging Basics

JavaScript Fundamentals

  • Variables (var, let, const)
  • Data Types and Type Checking
  • Comments and Code Organization
  • String Methods and Template Literals
  • Type Conversion and Coercion
  • Operators (Arithmetic, Comparison, Logical)

Control Flow

  • If/Else Statements
  • Switch Statements
  • Ternary Operator
  • Truthy and Falsy Values
  • Logical Operators and Short-Circuiting

Loops and Iteration

  • For Loops
  • While and Do-While Loops
  • For...of and For...in Loops
  • Break and Continue Statements

Functions

  • Function Declarations and Expressions
  • Arrow Functions
  • Function Parameters and Arguments
  • Return Statements and Values
  • Scope and Closures
  • Higher-Order Functions and Callbacks

Arrays

  • Array Basics and Creation
  • Array Methods: Adding and Removing Elements
  • Array Iteration Methods (forEach, map, filter)
  • Array Methods: find, some, every, reduce
  • Sorting, Reversing, and Array Transformation

Objects

  • Object Basics and Properties
  • Object Methods and 'this' Keyword
  • Object Destructuring
  • Object.keys, values, entries
  • Spread Operator and Object Cloning

DOM Manipulation

  • Introduction to the DOM
  • Selecting Elements (querySelector, getElementById)
  • Modifying Elements (textContent, innerHTML, style)
  • Creating and Removing Elements
  • Event Listeners and Event Handling
  • Event Object and Event Delegation

Asynchronous JavaScript

  • Understanding Asynchronous Code
  • setTimeout and setInterval
  • Callbacks and Callback Hell
  • Promises and Promise Chaining
  • Async/Await

Error Handling

  • Try, Catch, Finally
  • Throwing Custom Errors

Modern JavaScript Features

  • ES6+ Overview
  • Modules (import/export)
  • Optional Chaining and Nullish Coalescing
  • Rest and Spread Operators

Working with Data

  • JSON (Parse and Stringify)
  • Fetch API and HTTP Requests
  • Working with Local Storage

Advanced Concepts

  • Classes and Object-Oriented Programming
  • Array and Object Advanced Patterns
  • Regular Expressions Basics

Best Practices & Real-World Application

  • JavaScript Best Practices
  • Debugging Techniques and Tools
  • Building a Complete Interactive Project
Falytom logoFALYTOM

Learn technologies like HTML, CSS, JavaScript, React, NodeJS and more through interactive games, tutorials, components and free tools. Transform your businesses with AI chatbots, SEO-optimized websites, and professional development services.

© 2025 Tomilola Group
  • Facebook logo
  • Twitter logo
  • Instagram logo
  • LinkedIn logo
  • GitHub logo
  • YouTube logo