Skip to content

Instantly share code, notes, and snippets.

@indiesquidge
Last active January 20, 2024 15:03
Show Gist options
  • Save indiesquidge/5960274889e17102b5130e8bd2ce9002 to your computer and use it in GitHub Desktop.
Save indiesquidge/5960274889e17102b5130e8bd2ce9002 to your computer and use it in GitHub Desktop.
Recreating Promise.all with async/await
/*
Let us re-create `Promise.all`
`Promise.all` method returns a promise that resolves when all of the promises in the iterable argument have resolved,
or rejects with the reason of the first passed promise that rejects.
Read more about `Promise.all` on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
A basic example would be something like this:
Promise.all([promise1, promise2, promise3])
.then(allResolvedData => console.log('here are the resolutions to the promises', allResolvedData))
*/
let allWithAsync = (...listOfPromises) => {
return new Promise(async resolve => {
let results = []
for (let promise of listOfPromises) {
results.push(await promise.then(async resolvedData => await resolvedData))
if (results.length === listOfPromises.length) resolve(results)
}
})
}
const promise1 = Promise.resolve('first')
const promise2 = new Promise((resolve, reject) => setTimeout(resolve, 1000, 'second'))
const promise3 = Promise.resolve('third')
allWithAsync(promise1, promise2, promise3)
.then(resolvedData => {
console.log(resolvedData) // ['first', 'second', 'third']
})
/*
This is good, and it returns our promise resolutions in the right order,
but what happens if our list includes something that is not a promise?
*/
const promise4 = 'promise4'
/*
This will break our current `allWithAsync` by telling us that `promise.then` is not a function for our new `promise4`.
We can fix this with a small change to our function that wraps all items in the `listOfPromises` in a `Promise.resolve`.
Doing this will return each item as a promise that is resolved with said item.
*/
allWithAsync = (...listOfPromises) => {
return new Promise(async resolve => {
let results = []
for (let promise of listOfPromises.map(Promise.resolve, Promise)) {
results.push(await promise.then(async resolvedData => await resolvedData))
if (results.length === listOfPromises.length) resolve(results)
}
})
}
allWithAsync(promise1, promise2, promise3, promise4)
.then(resolvedData => {
console.log(resolvedData) // ['first', 'second', 'third', 'fourth']
})
/*
This is looking pretty good. One last thing: rejection handling.
*/
const promise5 = Promise.reject('rejected!')
/*
As mentioned above, `Promise.all` will either return a promise that resolves when all of the promises in
the iterable argument have resolved, or rejects with the reason of the first passed promise that rejects.
Let's handle the rejection case.
So far, our `Promise.then` has only been dealing with the fulfillment scenario of each promise.
A quick look at the API shows us that `Promise.then` can take two arguments: a fulfillment and a rejection handler.
Notice that we are returning a new Promise from our function. `new Promise` takes a callback with two arguments.
We are using one right now: `resolve`. But the second argument is `reject`.
If we include this in our promise instantiation callback and call it in our `Promise.then` function,
we should get the error handling we are looking for!
*/
allWithAsync = (...listOfPromises) => {
return new Promise(async (resolve, reject) => {
let results = []
for (let promise of listOfPromises.map(Promise.resolve, Promise)) {
results.push(await promise.then(async resolvedData => await resolvedData, reject))
if (results.length === listOfPromises.length) resolve(results)
}
})
}
allWithAsync(promise1, promise2, promise3, promise4, promise5)
.then(resolvedData => {
console.log(resolvedData) // will not run since we have a rejection!
}, rejectionReason => console.log('reason:', rejectionReason)) // reason: rejected!
@francophongvu
Copy link

Hi, cstroliadavis
Did you test your code? I followed it, but it doesn't work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment