Asher Cohen
Back to posts

JavaScript Promise Methods Reference

Complete guide to JavaScript Promise methods — then, catch, finally, and all static methods with practical examples

Introduction

Promises are JavaScript's built-in solution for handling asynchronous operations. Understanding all Promise methods is essential for writing clean, maintainable async code. This reference covers every Promise method with practical examples.

Instance Methods

then()

Purpose: Handles a fulfilled (resolved) promise.

Signature: promise.then(onFulfilled, onRejected)

Parameters:

  • onFulfilled (optional): Function called when the promise is fulfilled
  • onRejected (optional): Function called when the promise is rejected

Returns: A new Promise that resolves with the return value of the callback

// Basic usage
const promise = Promise.resolve('Hello');

promise.then((value) => {
  console.log(value); // 'Hello'
  return value.toUpperCase();
}).then((result) => {
  console.log(result); // 'HELLO'
});

// Chaining multiple then() calls
fetch('/api/user')
  .then(response => response.json())
  .then(user => user.name)
  .then(name => console.log(name));

Important Notes:

  • then() always returns a new Promise
  • If onFulfilled returns a value, the new Promise resolves with that value
  • If onFulfilled throws an error, the new Promise rejects with that error
  • You can omit onFulfilled to skip to the next handler
// onFulfilled can be omitted
promise.then(null, (error) => {
  console.error(error);
});

// Better: use catch() for errors
promise.catch((error) => {
  console.error(error);
});

catch()

Purpose: Handles a rejected promise. Syntactic sugar for then(null, onRejected).

Signature: promise.catch(onRejected)

Parameters:

  • onRejected: Function called when the promise is rejected

Returns: A new Promise that resolves with the return value of the callback

// Basic error handling
fetch('/api/user')
  .then(response => response.json())
  .catch(error => {
    console.error('Failed to fetch user:', error);
    return { name: 'Guest' }; // Provide fallback value
  })
  .then(user => console.log(user.name));

// Catching specific errors
fetch('/api/user')
  .then(response => {
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    return response.json();
  })
  .catch(error => {
    if (error.message.includes('HTTP 404')) {
      console.log('User not found');
    } else if (error.message.includes('HTTP 500')) {
      console.log('Server error');
    } else {
      console.error('Unknown error:', error);
    }
  });

Important Notes:

  • catch() is equivalent to then(undefined, onRejected)
  • Errors in then() handlers are caught by subsequent catch()
  • A catch() handler can return a value to recover from errors
  • To re-throw an error, use throw error in the catch block
// Error recovery pattern
apiCall()
  .catch(error => {
    console.error('Primary failed, trying fallback');
    return fallbackCall(); // Returns a value or Promise
  })
  .then(result => {
    // Works with either primary or fallback result
  });

// Re-throwing errors
apiCall()
  .catch(error => {
    console.error('Logging error:', error);
    throw error; // Re-throw for upstream handler
  })
  .catch(error => {
    // Handle the re-thrown error
  });

finally()

Purpose: Called when a promise is settled (either fulfilled or rejected).

Signature: promise.catch(onFinally)

Parameters:

  • onFinally: Function called when the promise settles (no arguments passed)

Returns: A new Promise with the same result as the original promise

// Loading state management
let isLoading = false;

fetch('/api/data')
  .then(data => {
    // Handle success
  })
  .catch(error => {
    // Handle error
  })
  .finally(() => {
    isLoading = false; // Always executed
    console.log('Request completed');
  });

// Cleanup operations
let connection;

connectToDatabase()
  .then(conn => {
    connection = conn;
    return connection.query('SELECT * FROM users');
  })
  .then(results => {
    // Process results
  })
  .catch(error => {
    // Handle errors
  })
  .finally(() => {
    if (connection) {
      connection.close(); // Always close connection
    }
  });

Important Notes:

  • onFinally receives no arguments (unlike then/catch)
  • The Promise chain continues with the original result after finally()
  • If onFinally throws an error, the Promise rejects with that error
  • Perfect for cleanup, loading indicators, and resource management

Static Methods

Promise.resolve()

Purpose: Creates a Promise that resolves with a given value.

Signature: Promise.resolve(value)

Returns: A Promise that resolves with the provided value

// Convert a value to a Promise
const promise = Promise.resolve('Hello');
promise.then(console.log); // 'Hello'

// Convert thenable to Promise
const thenable = {
  then(resolve) {
    resolve('Resolved!');
  }
};
Promise.resolve(thenable).then(console.log); // 'Resolved!'

// If already a Promise, returns the same Promise
const existingPromise = Promise.resolve('test');
Promise.resolve(existingPromise) === existingPromise; // true

// Practical usage: normalize sync/async functions
const maybeAsync = (value, isAsync) => {
  if (isAsync) {
    return fetch('/api/data').then(res => res.json());
  }
  return Promise.resolve(value); // Wrap sync value
};

Promise.reject()

Purpose: Creates a Promise that rejects with a given reason.

Signature: Promise.reject(reason)

Returns: A Promise that rejects with the provided reason

// Create a rejected Promise
const error = new Error('Something failed');
Promise.reject(error).catch(console.error);

// Practical usage: fail fast in conditional logic
const getUser = (id) => {
  if (!id) {
    return Promise.reject(new Error('ID is required'));
  }
  return fetch(`/api/users/${id}`).then(res => res.json());
};

// Reject with custom error types
Promise.reject(new TypeError('Invalid type'))
  .catch(error => {
    if (error instanceof TypeError) {
      // Handle type error
    }
  });

Promise.all()

Purpose: Waits for all Promises to resolve, or rejects if any Promise rejects.

Signature: Promise.all(iterable)

Returns: A Promise that resolves with an array of all results, or rejects with the first error

// Wait for multiple promises
const [user, posts, comments] = await Promise.all([
  fetch('/api/user').then(res => res.json()),
  fetch('/api/posts').then(res => res.json()),
  fetch('/api/comments').then(res => res.json())
]);

// All must succeed - if one fails, all fail
Promise.all([
  Promise.resolve(1),
  Promise.reject(new Error('Failed')),
  Promise.resolve(3)
]).catch(error => {
  console.error(error.message); // 'Failed'
});

// Practical usage: parallel API calls
const fetchAllData = async () => {
  try {
    const [users, products, orders] = await Promise.all([
      fetch('/api/users').then(r => r.json()),
      fetch('/api/products').then(r => r.json()),
      fetch('/api/orders').then(r => r.json())
    ]);
    return { users, products, orders };
  } catch (error) {
    console.error('Failed to load dashboard:', error);
    throw error;
  }
};

Important Notes:

  • All Promises must resolve for Promise.all() to resolve
  • If any Promise rejects, Promise.all() immediately rejects
  • Results are returned in the same order as the input array
  • Great for parallel operations where all must succeed

Promise.allSettled()

Purpose: Waits for all Promises to settle (resolve or reject).

Signature: Promise.allSettled(iterable)

Returns: A Promise that resolves with an array of result objects with { status, value/reason }

// Wait for all promises regardless of outcome
const results = await Promise.allSettled([
  Promise.resolve('Success'),
  Promise.reject(new Error('Failed')),
  Promise.resolve('Also success')
]);

console.log(results);
// [
//   { status: 'fulfilled', value: 'Success' },
//   { status: 'rejected', reason: Error: Failed },
//   { status: 'fulfilled', value: 'Also success' }
// ]

// Practical usage: batch operations with partial failures
const emailResults = await Promise.allSettled(
  emails.map(email => sendEmail(email))
);

const successful = emailResults.filter(r => r.status === 'fulfilled');
const failed = emailResults.filter(r => r.status === 'rejected');

console.log(`Sent ${successful.length}, Failed ${failed.length}`);

Important Notes:

  • Never rejects - always resolves with status array
  • Each result has status ('fulfilled' or 'rejected')
  • Fulfilled results have value, rejected have reason
  • Perfect for batch operations where partial success is acceptable

Promise.race()

Purpose: Returns the first Promise that settles (resolves or rejects).

Signature: Promise.race(iterable)

Returns: A Promise that settles with the first Promise's result

// Race between multiple promises
const winner = await Promise.race([
  fetch('/api/primary'),
  fetch('/api/backup'),
  fetch('/api/fallback')
]);

// Timeout pattern
const withTimeout = (promise, ms) => {
  const timeout = new Promise((_, reject) => {
    setTimeout(() => reject(new Error('Timeout')), ms);
  });
  return Promise.race([promise, timeout]);
};

// Usage
try {
  const data = await withTimeout(
    fetch('/api/slow-endpoint').then(r => r.json()),
    5000 // 5 second timeout
  );
} catch (error) {
  if (error.message === 'Timeout') {
    console.error('Request took too long');
  }
}

Important Notes:

  • Returns immediately when first Promise settles
  • If first is fulfilled, race() fulfills; if rejected, race() rejects
  • Other Promises continue running (not cancelled)
  • Useful for timeouts and fallback strategies

Promise.any()

Purpose: Returns the first Promise that fulfills, or rejects if all Promises reject.

Signature: Promise.any(iterable)

Returns: A Promise that fulfills with the first successful result, or rejects with AggregateError

// Get first successful result
const result = await Promise.any([
  fetch('/api/primary').then(r => r.json()),
  fetch('/api/backup').then(r => r.json()),
  fetch('/api/fallback').then(r => r.json())
]);

// If all fail, get AggregateError
try {
  const result = await Promise.any([
    Promise.reject(new Error('Failed 1')),
    Promise.reject(new Error('Failed 2'))
  ]);
} catch (error) {
  if (error instanceof AggregateError) {
    console.log('All promises rejected:', error.errors);
    // error.errors is an array of all rejection reasons
  }
}

// Practical usage: try multiple CDNs
const loadFromFastestCDN = async () => {
  try {
    const response = await Promise.any([
      fetch('https://cdn1.example.com/data.json'),
      fetch('https://cdn2.example.com/data.json'),
      fetch('https://cdn3.example.com/data.json')
    ]);
    return await response.json();
  } catch (error) {
    throw new Error('All CDNs failed');
  }
};

Important Notes:

  • Only fulfills on success, ignores rejections
  • Rejects with AggregateError only if ALL Promises reject
  • AggregateError.errors contains all rejection reasons
  • ES2021 feature - check browser support

Error Handling Best Practices

Always Handle Errors

// ❌ Unhandled promise rejection
fetch('/api/data').then(data => process(data));

// ✅ Always add catch
fetch('/api/data')
  .then(data => process(data))
  .catch(error => console.error(error));

// ✅ Or use async/await with try-catch
try {
  const data = await fetch('/api/data').then(r => r.json());
  process(data);
} catch (error) {
  console.error(error);
}

Chain Errors Properly

// ❌ Error can be lost
promise
  .then(handler)
  .catch(logError)
  .then(continueProcessing); // Runs even if error occurred

// ✅ Re-throw or handle
promise
  .then(handler)
  .catch(error => {
    logError(error);
    throw error; // Re-throw to stop chain
  });

Use Specific Error Types

class APIError extends Error {
  constructor(status, message) {
    super(message);
    this.status = status;
    this.name = 'APIError';
  }
}

fetch('/api/data')
  .then(response => {
    if (!response.ok) {
      throw new APIError(response.status, 'Request failed');
    }
    return response.json();
  })
  .catch(error => {
    if (error instanceof APIError) {
      handleAPIError(error.status);
    } else {
      handleGenericError(error);
    }
  });

Summary Table

MethodTypePurposeReturns
then()InstanceHandle fulfillmentNew Promise
catch()InstanceHandle rejectionNew Promise
finally()InstanceCleanup on settleNew Promise
resolve()StaticCreate resolved PromisePromise
reject()StaticCreate rejected PromisePromise
all()StaticWait for all (fail-fast)Promise array
allSettled()StaticWait for all (no fail)Status array
race()StaticFirst to settleFirst result
any()StaticFirst to fulfillFirst success

Conclusion

Mastering Promise methods gives you complete control over asynchronous operations. Use:

  • then()/catch()/finally() for handling individual Promises
  • Promise.all() when all operations must succeed
  • Promise.allSettled() for batch operations with partial failures
  • Promise.race() for timeouts and fallbacks
  • Promise.any() when you need the first successful result

Combine these methods to build robust, error-resistant async code.

#javascript #async #promises #reference #web-development