What is a Promise in JavaScript?
Promises are a fundamental feature in modern JavaScript, providing a robust way to handle asynchronous operations. They represent the eventual completion (or failure) of an asynchronous operation and its resulting value, making asynchronous code easier to write, read, and manage than traditional callback-based approaches.
What is a Promise?
A Promise in JavaScript is an object that represents the eventual completion or failure of an asynchronous operation. It acts as a placeholder for a value that is not yet known, allowing you to attach callbacks that will execute once the asynchronous operation has completed.
Promises are designed to manage asynchronous code in a more structured and readable manner, helping to mitigate issues like 'callback hell' by providing a cleaner way to handle sequential asynchronous tasks and error propagation.
States of a Promise
- Pending: Initial state, neither fulfilled nor rejected.
- Fulfilled (Resolved): Meaning that the operation completed successfully.
- Rejected: Meaning that the operation failed.
Pending
When a promise is in the 'pending' state, the asynchronous operation it represents is still ongoing. It has not yet produced a result (success or failure).
Fulfilled (Resolved)
A promise enters the 'fulfilled' state when the asynchronous operation completes successfully. The promise then holds a resulting value, which can be accessed by consumers.
Rejected
If the asynchronous operation encounters an error or fails, the promise enters the 'rejected' state. In this state, the promise holds an error object or reason for the failure.
Creating a Promise
You can create a new promise using the Promise constructor, which takes an executor function as an argument. The executor function receives two arguments: resolve and reject, which are functions used to change the promise's state.
const myPromise = new Promise((resolve, reject) => {
const success = true;
if (success) {
setTimeout(() => resolve('Operation successful!'), 1000);
} else {
setTimeout(() => reject('Operation failed.'), 1000);
}
});
Consuming a Promise
Promises are consumed using .then(), .catch(), and .finally() methods. .then() handles fulfillment, .catch() handles rejection, and .finally() executes regardless of the outcome.
myPromise
.then(value => {
console.log(value); // 'Operation successful!'
})
.catch(error => {
console.error(error); // 'Operation failed.'
})
.finally(() => {
console.log('Promise finished.');
});
Promise Chaining
One of the most powerful features of Promises is chaining, which allows you to perform a sequence of asynchronous operations. Each .then() method returns a new promise, enabling you to chain multiple .then() calls.
function fetchData() {
return new Promise(resolve => {
setTimeout(() => resolve('Data 1'), 500);
});
}
function processData(data) {
return new Promise(resolve => {
setTimeout(() => resolve(`${data} processed`), 500);
});
}
fetchData()
.then(data => {
console.log(data); // Data 1
return processData(data);
})
.then(processed => {
console.log(processed); // Data 1 processed
})
.catch(error => {
console.error('Error in chain:', error);
});
Common Promise Methods
| Method | Description |
|---|---|
| Promise.all(iterable) | Waits for all promises in the iterable to be fulfilled, or for any one to be rejected. |
| Promise.race(iterable) | Returns a promise that fulfills or rejects as soon as one of the promises in the iterable fulfills or rejects. |
| Promise.allSettled(iterable) | Waits for all promises to settle (either fulfill or reject) and returns an array of objects describing the outcome of each promise. |
| Promise.any(iterable) | Returns a promise that fulfills as soon as any of the promises in the iterable fulfills, or rejects if all of them reject. |
Why use Promises?
- Improved readability and maintainability of asynchronous code.
- Better error handling compared to nested callbacks (callback hell).
- Easier to compose and chain multiple asynchronous operations.
- Standardized way to handle asynchronous patterns in JavaScript.