I'm working with some old code and I'm trying to return results for two arrays of promises.
So basically body contains first
and second
which are arrays of ids. I know that the below code works for a small array of of 1 to 5 ids, but if I were to do a few hundred, would the resolve fire before I get the hundred of results from both promise arrays?
const doSomething = (body) => {
return new Promise((resolve, reject) => {
const promisesOne = body.first.map((id) =>
doSomethingOne(id)
);
const promisesTwo = body.second.map((id) =>
doSomethingTwo(id)
);
let response = {
first: {}
second: {}
headers: 'mock headers'
};
Promise.all(promisesOne).then((results) => {
response.first = results;
});
Promise.all(promisesTwo).then((results) => {
response.second = results;
});
resolve(response);
});
};
Also I won't be able to refactor this to async/await as this codebase does not use it.
I'm working with some old code and I'm trying to return results for two arrays of promises.
So basically body contains first
and second
which are arrays of ids. I know that the below code works for a small array of of 1 to 5 ids, but if I were to do a few hundred, would the resolve fire before I get the hundred of results from both promise arrays?
const doSomething = (body) => {
return new Promise((resolve, reject) => {
const promisesOne = body.first.map((id) =>
doSomethingOne(id)
);
const promisesTwo = body.second.map((id) =>
doSomethingTwo(id)
);
let response = {
first: {}
second: {}
headers: 'mock headers'
};
Promise.all(promisesOne).then((results) => {
response.first = results;
});
Promise.all(promisesTwo).then((results) => {
response.second = results;
});
resolve(response);
});
};
Also I won't be able to refactor this to async/await as this codebase does not use it.
Share Improve this question asked Sep 12, 2022 at 2:57 ffx292ffx292 7093 gold badges20 silver badges35 bronze badges 3-
FYI your code always returns
resolve()
before you get results, no matter how large your arrays are – Phil Commented Sep 12, 2022 at 3:10 -
Avoid the
Promise
constructor antipattern! – Bergi Commented Sep 12, 2022 at 4:04 - I would if I could... Unfortunately, it isn't my codebase. – ffx292 Commented Sep 13, 2022 at 1:28
2 Answers
Reset to default 5would the resolve fire before I get the ... results from both promise arrays?
Yes, absolutely because you aren't waiting for them to resolve.
Simply wrap the two Promise.all()
promises in another Promise.all()
to wait for everything then create the final object you want.
const doSomething = (body) => {
return Promise.all([
Promise.all(body.first.map(doSomethingOne)),
Promise.all(body.second.map(doSomethingTwo)),
]).then(([first, second]) => ({
first,
second,
headers: "mock headers",
}));
};
You could make this generic by creating a map of body
property names to their corresponding mapping function. For example
const mappers = {
first: doSomethingOne,
second: doSomethingTwo,
};
const doSomething = (body) => {
return Promise.all(
Object.entries(mappers).map(([key, mapper]) =>
Promise.all(body[key].map(mapper)).then((data) => ({ [key]: data }))
)
)
.then((results) => Object.assign({ headers: "mock headers" }, ...results));
};
Your code will not work at the moment - the resolve(response)
will run before either of the Promise.all
s are done.
First, refactor your .first
and .second
(etc) properties so that they're arrays, rather than unique string properties. Then, it'll be easy to .map
them with two Promise.all
s - one to wait for an individual array to fulfill, and an outer one to wait for all arrays to fulfill.
The same thing should be done for the doSomethingOne
etc functions - to make the code easy to work with, use an array of functions instead of having many standalone identifiers.
Also, there's no need for the explicit Promise construction antipattern.
const doSomethings = [
doSomethingOne, // define these functions here
doSomethingTwo,
];
const doSomething = (body) => Promise.all(
body.arrayOfArraysOfIds.map(
(arr, i) => Promise.all(
arr.map(id => doSomethings[i](id))
)
)
)
.then((results) => ({
headers: 'mock headers',
results,
});