JavaScript12 min read

JavaScript Promises: From Basics to Advanced Patterns

Master JavaScript Promises for handling asynchronous operations. Learn promise chaining, error handling, Promise.all, Promise.race, and modern async patterns.

Alex Thompson
December 18, 2025
0.0k0

Promises are the foundation of asynchronous JavaScript. They represent a value that may not be available yet but will be resolved in the future.

What is a Promise?

A Promise is an object representing the eventual completion or failure of an async operation. It can be in one of three states: pending, fulfilled, or rejected.

```javascript // Creating a simple promise const myPromise = new Promise((resolve, reject) => { const success = true; setTimeout(() => { if (success) { resolve('Operation successful!'); } else { reject('Operation failed!'); } }, 1000); });

// Using the promise myPromise .then(result => console.log(result)) .catch(error => console.error(error)); ```

Promise Chaining

Chain multiple async operations together. Each `.then()` returns a new promise.

```javascript fetch('https://api.example.com/user/1') .then(response => response.json()) .then(user => { console.log('User:', user.name); return fetch(`https://api.example.com/posts/${user.id}`); }) .then(response => response.json()) .then(posts => { console.log('Posts:', posts); }) .catch(error => { console.error('Error:', error); }); ```

Promise.all - Wait for Multiple Promises

Run multiple promises in parallel and wait for all to complete.

```javascript const promise1 = fetch('https://api.example.com/users'); const promise2 = fetch('https://api.example.com/posts'); const promise3 = fetch('https://api.example.com/comments');

Promise.all([promise1, promise2, promise3]) .then(responses => { // All promises resolved return Promise.all(responses.map(r => r.json())); }) .then(([users, posts, comments]) => { console.log('Users:', users); console.log('Posts:', posts); console.log('Comments:', comments); }) .catch(error => { // If any promise rejects console.error('One of the requests failed:', error); }); ```

Promise.race - First to Finish Wins

Use `Promise.race()` when you want the result of whichever promise completes first.

```javascript const slowPromise = new Promise(resolve => setTimeout(() => resolve('Slow'), 3000) );

const fastPromise = new Promise(resolve => setTimeout(() => resolve('Fast'), 1000) );

Promise.race([slowPromise, fastPromise]) .then(result => console.log(result)); // 'Fast'

// Timeout pattern const fetchWithTimeout = (url, timeout = 5000) => { return Promise.race([ fetch(url), new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), timeout) ) ]); }; ```

Error Handling

Handle errors properly in promise chains. Errors bubble up to the nearest `.catch()`.

```javascript fetch('https://api.example.com/data') .then(response => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .then(data => { console.log(data); }) .catch(error => { console.error('Failed to fetch:', error.message); }) .finally(() => { console.log('Request completed'); }); ```

Async/Await - Modern Promise Syntax

Async/await makes promises easier to work with. It's syntactic sugar over promises.

```javascript // Traditional promise chain function getUser(id) { return fetch(`https://api.example.com/user/${id}`) .then(response => response.json()) .then(user => user); }

// With async/await async function getUser(id) { const response = await fetch(`https://api.example.com/user/${id}`); const user = await response.json(); return user; }

// Error handling with async/await async function fetchData() { try { const response = await fetch('https://api.example.com/data'); const data = await response.json(); return data; } catch (error) { console.error('Error fetching data:', error); throw error; } } ```

Real-World Example

Complete example combining everything: fetching user data, their posts, and handling errors.

```javascript async function getUserDashboard(userId) { try { // Fetch user and posts in parallel const [userResponse, postsResponse] = await Promise.all([ fetch(`https://api.example.com/users/${userId}`), fetch(`https://api.example.com/posts?userId=${userId}`) ]);

// Check if responses are ok if (!userResponse.ok || !postsResponse.ok) { throw new Error('Failed to fetch data'); }

// Parse JSON in parallel const [user, posts] = await Promise.all([ userResponse.json(), postsResponse.json() ]);

// Return combined data return { user, posts, postCount: posts.length }; } catch (error) { console.error('Dashboard error:', error); return null; } }

// Usage getUserDashboard(123).then(dashboard => { if (dashboard) { console.log(`${dashboard.user.name} has ${dashboard.postCount} posts`); } }); ```

#JavaScript#Promises#Async

Common Questions & Answers

Q1

What are the three states of a Promise?

A

Promises have three states: 1) Pending - initial state, operation not completed yet. 2) Fulfilled - operation completed successfully, has a value. 3) Rejected - operation failed, has an error reason. Once settled (fulfilled or rejected), a promise cannot change state.

javascript
const promise = new Promise((resolve, reject) => {
  // Pending state
  console.log('Promise is pending...');
  
  const success = Math.random() > 0.5;
  
  setTimeout(() => {
    if (success) {
      resolve('Success!'); // Fulfilled state
    } else {
      reject('Failed!'); // Rejected state
    }
  }, 1000);
});
Q2

How does Promise.all() differ from Promise.race()?

A

Promise.all() waits for ALL promises to resolve and returns an array of results. If any promise rejects, the entire Promise.all() rejects. Promise.race() returns the first promise to settle (resolve or reject), ignoring the others. Use Promise.all() when you need all results, Promise.race() for timeout scenarios or fastest response.

javascript
// Promise.all - waits for all
const all = await Promise.all([
  fetch('/api/users'),
  fetch('/api/posts'),
  fetch('/api/comments')
]);
// Returns array: [users, posts, comments]
// Fails if ANY request fails

// Promise.race - first to finish wins
const race = await Promise.race([
  fetch('/api/data'),
  new Promise((_, reject) => 
    setTimeout(() => reject('Timeout'), 5000)
  )
]);
// Returns first completed promise
// Useful for timeouts