I'm trying to wait for a bunch of promises to plete. I know I can do this with Promise.all
, but I can't figure out what to do when one of those promises pushes a new promise into the promise list.
Example:
asyncFunction(...).then(result => {
// do something
});
asyncFunction(...).then(result => {
for(let row of result) {
asyncFunction(row);
}
});
console.log(promises.length); // 2
await Promise.all(promises);
console.log(promises.length); // 5
Where asyncFunction
is something like:
const asyncFunction = (...args) => {
let result = new Promise((resolve, reject) => {
pool.query(...args, (err, rows, fields) => {
if (err) {
reject(err);
} else {
resolve(rows);
}
});
});
promises.push(result);
return result;
};
What's happened here is that the first two calls to asyncFunction
push promises into my promises
array, so promises.length
is 2. However, after waiting for them to plete, the 2nd one pushes a bunch of new promises into the array after Promise.all
has already evaluated that array, so they're not awaited.
So, how can I wait for all the promises, plus any new ones? Simply calling await Promise.all(promises)
twice would work in this example, but this could go on ad infinitum.
I'm trying to wait for a bunch of promises to plete. I know I can do this with Promise.all
, but I can't figure out what to do when one of those promises pushes a new promise into the promise list.
Example:
asyncFunction(...).then(result => {
// do something
});
asyncFunction(...).then(result => {
for(let row of result) {
asyncFunction(row);
}
});
console.log(promises.length); // 2
await Promise.all(promises);
console.log(promises.length); // 5
Where asyncFunction
is something like:
const asyncFunction = (...args) => {
let result = new Promise((resolve, reject) => {
pool.query(...args, (err, rows, fields) => {
if (err) {
reject(err);
} else {
resolve(rows);
}
});
});
promises.push(result);
return result;
};
What's happened here is that the first two calls to asyncFunction
push promises into my promises
array, so promises.length
is 2. However, after waiting for them to plete, the 2nd one pushes a bunch of new promises into the array after Promise.all
has already evaluated that array, so they're not awaited.
So, how can I wait for all the promises, plus any new ones? Simply calling await Promise.all(promises)
twice would work in this example, but this could go on ad infinitum.
-
1
Don't push to the pool at arbitrary times. Wait until the pool is filled,
then
callPromise.all
on it. Don't pool everything together in one array if you need to push at distinct times, rather callPromise.all
multiple times. – Bergi Commented Jun 29, 2016 at 18:12 - 1 @Bergi The new promises are created as a result of a previous async result. – user2864740 Commented Jun 29, 2016 at 18:15
- 1 Does this help? – Bergi Commented Jun 29, 2016 at 18:16
-
@user2864740: So? Then those new promises should be
Promise.all
'd, and be chained to the previous async result viathen
so that you get a promise for them. – Bergi Commented Jun 29, 2016 at 18:17 - @Bergi Yes, I think that's more or less the same question. The posted solution could probably be made slightly more efficient by not re-evaluating the already checked promises though. – mpen Commented Jun 29, 2016 at 18:24
3 Answers
Reset to default 5You can write a recursive all function that re-evaluates the status of the list after each iteration:
function recursiveAll( array ) {
// Wait for the promises to resolve
return Promise.all( array ).then(function( result ) {
// If no new promises were added, return the result
if ( result.length == array.length )
return result;
// If new promises were added, re-evaluate the array.
return recursiveAll( array );
});
}
That's the problem with functions that have side effects.
Your code is a bit to abstract to give you a moe precise answer, but I would recend you to pletely drop the promises
-Array.
const asyncFunction = (...args) => {
return new Promise((resolve, reject) => {
pool.query(...args, (err, rows, fields) => {
if (err) {
reject(err);
} else {
resolve(rows);
}
});
});
}
and
asyncFunction(...).then(result => Promise.all(result.map(row => asyncFunction(row))) );
As far as I understand your intentions, this should result in a nested structure of Arrays within Arrays, in the worst case, wich now only has to be flattened to get ALL values, and those wich are triggered by the previous ones.
I think simply replacing Promise.all
with this should work fine:
while(promises.length) {
await promises.shift();
}