What is the Promise API?
In the context of Promises, API refers to the set of built-in methods that JavaScript provides to work with Promises efficiently. These methods allow developers to handle multiple Promises simultaneously, control their resolution or rejection, and streamline asynchronous operations.
`Promise.resolve` and `Promise.reject`
- Promise.resolve(value): Think of this method as an instant promise creator. When you pass a value to it, it immediately resolves with that value.
- Promise.reject(reason): On the flip side, this method instantly returns a promise that rejects with the reason you provide. The reason can be anything: an error, a message, or any value you choose.
These methods give you the power to manage promises explicitly, without waiting for something asynchronous to happen. They are incredibly useful for controlling the flow of your code and making promises behave exactly how you want them to.
Imagine you're building a complex app, and sometimes you need to resolve or reject promises right away, without having to deal with any delay. This is where Promise.resolve and Promise.reject shine. They’re your little helpers that make sure your promises are always under your control.
Here's how you can make magic happen:
Promise.resolve('Everything is awesome!').then(console.log); // 'Everything is awesome!'
Promise.reject('Oh no, something went wrong!').catch(console.error); // 'Oh no, something went wrong!'In this example:
Promise.resolve('Everything is awesome!'): This immediately resolves the promise and outputs "Everything is awesome!" withthen(). It's like a cheerful success message.Promise.reject('Oh no, something went wrong!'): This rejects the promise right away and catches the error withcatch(), giving you a chance to handle the failure gracefully.
What's beautiful about this? You control the flow. Whether it's success or failure, you decide when and how your promises should resolve or reject. It's like having your own promise-powered universe at your fingertips.
`Promise.all`
The Promise.all() method takes an array of promises and returns a single promise. This returned promise:
- Resolves when all input promises have resolved.
- Rejects immediately if any promise rejects, and the rejection reason is passed along.
Key Points:
- Success Case: If all promises resolve, an array of resolved values (in the same order) is returned.
- Failure Case: If even one promise rejects,
Promise.all()immediately rejects with that error.
const promise1 = Promise.resolve(10); // Resolved immediately
const promise2 = new Promise(resolve => setTimeout(() => resolve(20), 1000)); // Resolves after 1 sec
const promise3 = Promise.resolve(30); // Resolved immediately
Promise.all([promise1, promise2, promise3])
.then(values => {
console.log(values); // [10, 20, 30] (after 1 second)
})
.catch(error => console.error(error));When Does `Promise.all` Reject?If any promise in the array rejects, Promise.all() immediately rejects, skipping any remaining promises.
const promise1 = Promise.resolve(10);
const promise2 = new Promise((_, reject) => setTimeout(() => reject("Error occurred"), 500));
const promise3 = Promise.resolve(30);
Promise.all([promise1, promise2, promise3])
.then(values => {
console.log(values); // This will not run
})
.catch(error => {
console.error(error); // "Error occurred" (after 500ms)
});Best Practices:- Use
Promise.all()when all tasks must be completed before proceeding. - Be cautious of immediate failure if any promise rejects.
- For handling both resolved and rejected promises, consider using
Promise.allSettled().
`Promise.race`
The Promise.race() method takes an array of promises and returns a single promise that:
- Resolves or rejects as soon as any of the input promises settles (resolves or rejects).
- The result is from the first settled promise, regardless of whether it resolves or rejects.
In this example, we have two promises: one resolves in 500ms (fast), and the other resolves in 1000ms (slow). Since the fast promise settles first, its value is returned.
const fast = new Promise(resolve => setTimeout(() => resolve('Fast!'), 500));
const slow = new Promise(resolve => setTimeout(() => resolve('Slow!'), 1000));
Promise.race([fast, slow]).then(value => {
console.log(value); // 'Fast!' (after 500ms)
});Handling Rejections:If the first settled promise rejects, Promise.race() will reject with that error.
const fastReject = new Promise((_, reject) => setTimeout(() => reject('Error!'), 300));
const slowResolve = new Promise(resolve => setTimeout(() => resolve('Success!'), 1000));
Promise.race([fastReject, slowResolve])
.then(value => {
console.log(value); // This won't execute
})
.catch(error => {
console.error(error); // "Error!" (after 300ms)
});Use Cases:- Timeout Handling: Set a timeout for an API request by racing it against a delay.
- Fastest Response: Fetch from multiple sources and use the first successful response.
- Performance Optimization: Execute tasks in parallel and use the fastest result.
Here, if the API takes longer than 2 seconds, we return a timeout error instead.
const fetchData = new Promise(resolve => setTimeout(() => resolve('Data received!'), 3000));
const timeout = new Promise((_, reject) => setTimeout(() => reject('Request timed out!'), 2000));
Promise.race([fetchData, timeout])
.then(value => console.log(value))
.catch(error => console.error(error)); // "Request timed out!" (after 2000ms)Key Takeaways:Promise.race()is useful when you only care about the first settled promise.- If one promise resolves and another rejects, whichever happens first determines the outcome.
- Commonly used for implementing timeouts and selecting the fastest response.
`Promise.allSettled`
The Promise.allSettled() method takes an array of promises and returns a new promise that:
- Waits for all input promises to settle (either resolve or reject).
- Returns an array of objects describing the outcome of each promise.
- Unlike
Promise.all(), it does not stop if a promise rejects; it waits for all.
In this example, we have three promises:
p1resolves immediately.p2rejects immediately.p3resolves after 1 second.
const p1 = Promise.resolve('Success');
const p2 = Promise.reject('Error occurred');
const p3 = new Promise(resolve => setTimeout(() => resolve('Done'), 1000));
Promise.allSettled([p1, p2, p3]).then(results => {
console.log(results);
/* Output:
[
{ status: 'fulfilled', value: 'Success' },
{ status: 'rejected', reason: 'Error occurred' },
{ status: 'fulfilled', value: 'Done' }
]
*/
});Handling Results:The returned array contains objects with:
- `status` -
"fulfilled"if the promise resolved,"rejected"if it failed. - `value` - Present only if the promise resolved.
- `reason` - Present only if the promise rejected.
- Batch Processing: When working with multiple independent requests where failure of one should not stop others.
- Logging & Debugging: When you need detailed results of all operations.
- Graceful Handling: Helps handle both successes and failures efficiently.
In this example, we fetch data from different APIs. Some may fail, but we want results from all.
const fetchUser = new Promise(resolve => setTimeout(() => resolve('User data'), 500));
const fetchPosts = new Promise((_, reject) => setTimeout(() => reject('Failed to fetch posts'), 700));
const fetchComments = new Promise(resolve => setTimeout(() => resolve('Comments data'), 1000));
Promise.allSettled([fetchUser, fetchPosts, fetchComments]).then(results => {
results.forEach((result, index) => {
console.log(`Promise ${index + 1}: `, result);
});
});Key Takeaways:Promise.allSettled()is useful when you need results from all promises regardless of success or failure.- Unlike
Promise.all(), it never rejects the overall promise. - Great for use cases where partial success is acceptable.
`Promise.any`
The Promise.any() method takes an array of promises and returns a single promise that:
- Resolves as soon as any of the input promises resolve.
- If all promises reject, it returns an
AggregateError.
Note : AggregateError is an error object in JavaScript used specifically with Promise.any(). It represents a collection of individual errors that occurred during the execution of multiple promises when at least one of them is resolved successfully.
Example:In this example:
p1rejects immediately.p2resolves after 1 second.p3rejects immediately.
const p1 = Promise.reject('Error 1');
const p2 = new Promise(resolve => setTimeout(() => resolve('First success!'), 1000));
const p3 = Promise.reject('Error 2');
Promise.any([p1, p2, p3]).then(value => {
console.log(value); // 'First success!' (after 1 second)
}).catch(error => console.error(error));Handling Errors:If all input promises reject, Promise.any() rejects with an AggregateError, which contains all rejection reasons.
const p1 = Promise.reject('Error A');
const p2 = Promise.reject('Error B');
const p3 = Promise.reject('Error C');
Promise.any([p1, p2, p3]).catch(error => {
console.log(error instanceof AggregateError); // true
console.log(error.errors); // ['Error A', 'Error B', 'Error C']
});Use Cases:- First Available Response: Fetching data from multiple sources and using the fastest response.
- Quick Fallbacks: Trying different strategies and picking the first successful one.
- Resilient User Experience: Avoiding complete failure if at least one operation succeeds.
Here, we request data from multiple APIs and take the first successful response.
const fetchFromAPI1 = new Promise((_, reject) => setTimeout(() => reject('API 1 failed'), 500));
const fetchFromAPI2 = new Promise(resolve => setTimeout(() => resolve('API 2 data'), 1000));
const fetchFromAPI3 = new Promise(resolve => setTimeout(() => resolve('API 3 data'), 1500));
Promise.any([fetchFromAPI1, fetchFromAPI2, fetchFromAPI3]).then(data => {
console.log('First successful response:', data);
});Key Takeaways:Promise.any()resolves with the first successful promise.- If all promises fail, it rejects with an AggregateError containing all errors.
- Great for fault-tolerant operations where at least one success is acceptable.
Promise.all, race, allSettled, any with a scenario
Promise.all – Waiting for All Bookings to Resolve
Scenario: You need all the bookings (flight, hotel, and car rental) to be successful to confirm the user's vacation package.
const bookFlight = fetch('https://api.flightservice.com/book');
const bookHotel = fetch('https://api.hotelservice.com/book');
const bookCar = fetch('https://api.carservice.com/book');
Promise.all([bookFlight, bookHotel, bookCar])
.then(responses => Promise.all(responses.map(response => response.json())))
.then(data => console.log('All bookings successful:', data))
.catch(error => console.error('Booking failed:', error));Note : This URL is just used for scenario, meaning it is not real. Same for race, allSettled, any.
Promise.allSettled – Waiting for All Bookings to SettleScenario: You want to know the status of each booking, whether successful or failed, and give feedback on each step.
const bookFlight = fetch('https://api.flightservice.com/book');
const bookHotel = fetch('https://api.hotelservice.com/book');
const bookCar = fetch('https://api.carservice.com/book');
Promise.allSettled([bookFlight, bookHotel, bookCar])
.then(results => {
results.forEach(result => {
if (result.status === 'fulfilled') {
console.log('Booking success:', result.value);
} else {
console.log('Booking failed:', result.reason);
}
});
});Promise.race – The First Successful Booking WinsScenario: You want to proceed as soon as one booking is confirmed (e.g., confirming the flight first), ignoring the other bookings for now.
const bookFlight = fetch('https://api.flightservice.com/book');
const bookHotel = fetch('https://api.hotelservice.com/book');
const bookCar = fetch('https://api.carservice.com/book');
Promise.race([bookFlight, bookHotel, bookCar])
.then(response => response.json())
.then(data => console.log('First successful booking:', data))
.catch(error => console.error('Error in first booking:', error));Promise.any – The First Successful Booking Wins (Ignore Rejections)Scenario: You want to continue with the first successful booking, even if some fail. This way, if one of the bookings (like hotel) fails, you can still proceed if the flight or car rental is successful.
const bookFlight = fetch('https://api.flightservice.com/book');
const bookHotel = fetch('https://api.hotelservice.com/book');
const bookCar = fetch('https://api.carservice.com/book');
Promise.any([bookFlight, bookHotel, bookCar])
.then(response => response.json())
.then(data => console.log('First successful booking:', data))
.catch(error => console.error('All bookings failed:', error));Explanation:
Promise.anywill resolve as soon as any one of the promises resolves. It will ignore the rejections of the other promises.- This is useful when you want to proceed as soon as any part of the process succeeds (e.g., confirming a flight) and don't care if some other bookings fail.
Handling Non-Promise Values with Promise Methods
One of the powerful features of Promise.all, Promise.allSettled, Promise.race, and Promise.any is that they can also handle non-promise values (like regular values or primitives). When you pass a non-promise value, it will automatically be wrapped in a resolved promise. This makes these methods flexible when dealing with mixed input types (both promises and regular values).
Promise.all with Non-Promise ValuesPromise.all will wait for all promises to resolve, but if you pass any non-promise value, it will treat it as a resolved promise.
const promise1 = Promise.resolve('Flight Booked!');
const promise2 = 'Hotel Booked!';
const promise3 = Promise.resolve('Car Rental Confirmed!');
Promise.all([promise1, promise2, promise3])
.then(results => console.log(results)); // ['Flight Booked!', 'Hotel Booked!', 'Car Rental Confirmed!']Explanation:
- In this example, the second value, 'Hotel Booked!', is not a promise. However,
Promise.allautomatically wraps it into a resolved promise, and the result is an array of resolved values.
Promise.allSettled with Non-Promise ValuesPromise.allSettled works similarly to Promise.all, but it provides the result of each promise, regardless of whether it was fulfilled or rejected.
const promise1 = Promise.resolve('Flight Booked!');
const promise2 = 'Hotel Booked!';
const promise3 = Promise.reject('Car Rental Failed!');
Promise.allSettled([promise1, promise2, promise3])
.then(results => console.log(results));
// [{status: 'fulfilled', value: 'Flight Booked!'}, {status: 'fulfilled', value: 'Hotel Booked!'}, {status: 'rejected', reason: 'Car Rental Failed!'}]Explanation:
Promise.allSettledwill resolve all non-promise values into resolved promises, and it will show you the status of each (fulfilled or rejected).- Even the non-promise value 'Hotel Booked!' is handled seamlessly as a resolved promise.
Promise.race with Non-Promise ValuesPromise.race returns as soon as the first promise resolves or rejects. Non-promise values are treated as resolved promises.
const promise1 = new Promise((resolve) => setTimeout(resolve, 100, 'Flight Booked!'));
const promise2 = 'Hotel Booked!';
const promise3 = new Promise((resolve) => setTimeout(resolve, 200, 'Car Rental Confirmed!'));
Promise.race([promise1, promise2, promise3])
.then(result => console.log(result)); // 'Hotel Booked!'Explanation:
- Here, 'Hotel Booked!' is a non-promise value.
Promise.racetreats it as a resolved promise, and since it’s the first value to resolve, it returns that result.
Promise.any with Non-Promise ValuesPromise.any resolves as soon as any promise resolves, and non-promise values are treated as resolved promises, too.
const promise1 = new Promise((resolve) => setTimeout(resolve, 100, 'Flight Booked!'));
const promise2 = 'Hotel Booked!';
const promise3 = new Promise((resolve) => setTimeout(resolve, 200, 'Car Rental Confirmed!'));
Promise.any([promise1, promise2, promise3])
.then(result => console.log(result)); // 'Hotel Booked!'Explanation:
Promise.anyresolves to the first fulfilled promise. Here, 'Hotel Booked!' is treated as a resolved promise and is returned because it's the first to be available.