JavaScript introduced Promise.allSettled in ES2020 to make working with multiple asynchronous operations easier. Unlike Promise.all, which short-circuits when a promise rejects, Promise.allSettled ensures that you get results from all promises, whether they succeed or fail.
In this tutorial, I’ll walk you through creating your own implementation of Promise.allSettled, focusing on building it from scratch. We will also explore how promises work behind the scenes, helping you understand the asynchronous behavior that makes JavaScript so powerful.
Before we jump into writing code, let's break down what Promise.allSettled does:
Each object in the array contains:
const promises = [ Promise.resolve('Success'), Promise.reject('Failure'), Promise.resolve('Complete') ]; Promise.allSettled(promises).then(results => { console.log(results); });
Output:
[ { status: 'fulfilled', value: 'Success' }, { status: 'rejected', reason: 'Failure' }, { status: 'fulfilled', value: 'Complete' } ]
This method is ideal when you need to wait for all promises to finish, regardless of whether they succeed or fail.
Even though this feature is now available in modern browsers, implementing it yourself offers a deeper understanding of how JavaScript promises work. Plus, it ensures compatibility with older environments that don’t support ES2020 features natively.
We’re going to create a function named allSettled that mimics the behavior of Promise.allSettled. Let’s build this step-by-step:
The function takes an array of promises and returns a new promise. This new promise will resolve when all the input promises settle (either resolve or reject).
function allSettled(promises) { // This will return a new promise that resolves when all promises settle return new Promise((resolve) => { // Implementation goes here }); }
For each promise in the array, we need to track whether it resolves or rejects. We’ll wrap each promise with a .then() and .catch() to capture its status:
function allSettled(promises) { return new Promise((resolve) => { let results = []; let count = 0; promises.forEach((promise, index) => { // Wrap the promise with a .then() and .catch() to capture the result promise .then((value) => { results[index] = { status: 'fulfilled', value }; }) .catch((reason) => { results[index] = { status: 'rejected', reason }; }) .finally(() => { count++; // Once all promises have settled, resolve the outer promise if (count === promises.length) { resolve(results); } }); }); }); }
1. Creating the Outer Promise:
The allSettled function returns a new Promise. This promise will resolve when all input promises have settled.
2. Looping Over Promises:
We loop through the promises array using .forEach. For each promise, we track its outcome with .then() (for resolved promises) and .catch() (for rejected promises).
3. Recording Results:
The result of each promise is stored in the results array. If the promise resolves, the object contains { status: 'fulfilled', value }. If it rejects, it stores { status: 'rejected', reason }.
4. Counting Settled Promises:
We use a count variable to track how many promises have settled. Each time a promise finishes (either through .then() or .catch()), we increment the count. Once count equals the length of the input array, we resolve the outer promise with the results array.
Now, let's test this custom implementation:
const promises = [ Promise.resolve('Success'), Promise.reject('Failure'), Promise.resolve('Complete') ]; Promise.allSettled(promises).then(results => { console.log(results); });
Output:
[ { status: 'fulfilled', value: 'Success' }, { status: 'rejected', reason: 'Failure' }, { status: 'fulfilled', value: 'Complete' } ]
As expected, the function waits for all promises to settle, and the results array gives us detailed information about each promise, including whether it resolved or rejected.
To reinforce understanding, let's break down how promises work:
Resolved (fulfilled) when the operation completes successfully.
Rejected when the operation fails.
Settled when it is either fulfilled or rejected
The then() method allows us to specify a function to be executed when the promise is resolved, while catch() allows us to handle rejections. Using finally() ensures that we handle the promise settling (either success or failure) without duplication.
Implementing Promise.allSettled yourself is a fantastic way to understand how promises work at a fundamental level. The key takeaway is that Promise.allSettled waits for all promises to finish, unlike Promise.all, which stops when it encounters a rejection.
By implementing this from scratch, you’ve also learned how to handle multiple asynchronous operations in a clean and efficient way. Now you can use this knowledge to work with promises in any JavaScript environment, including those that don’t natively support modern features.
The above is the detailed content of Tutorial: Implementing Polyfills Promise.allSettled From Scratch in JavaScript. For more information, please follow other related articles on the PHP Chinese website!