Reputation: 553
I am having difficulty understanding how to work with groups of promises that need to resolve together.
In my situation I want to make a series of promise calls based on an array of ids, and selectively add them to an output array. If this were PHP I would do something like:
$output = []
foreach($input as $id) {
$result1 = functioncall1($id);
$result2 = functioncall2($result1);
if ($result2 == 'some filter') {
$output[] = $result1;
}
}
This can't be done with an asynchronous call as the loop does not wait for the result to return. So I'm using promises with bluebird like this:
Promise.map(input, function(id) {
promisifedFunction1(id)
.then(function(result1) {
//process result1 some more
promisifedFunction2(result1)
.then(function(result2) {
//process result2 some more
if (result2 == 'some filter') {
return result1;
});
});
})
.then(function(output) {});
}
I am clearly missing something here because my output only ever contains an array of undefined. However it is apparently mapping and reaching the final then when I expect it to and those undefined arrays are only produced when the filtering oks it. The undefined is produced even if the filter just returns a literal string.
I'm clearing missing something but I'm struggling to fill in the gaps.
Upvotes: 2
Views: 1435
Reputation: 426
You can use Promise.all
var promise1 = new Promise(function (resolve, reject) {
// promise1 code here
resolve(true);
})
var promise2 = new Promise(function (resolve, reject) {
// promise2 code here
resolve(true);
})
var promise3 = new Promise(function (resolve, reject) {
// promise3 code here
resolve(true);
})
Here we have used 3 Promises and now if we have to execute code after resolving all Promises we can use Promise.all
Promise.all([promise1, promise2, promise3]).then(() => {
// code
});
Upvotes: 1
Reputation: 276596
You can do eta-reduction to make that code look a lot simpler:
Promise.map(input, promisifedFunction1)
.map(promisifiedFunction2)
.filter(v => v === 'someFilter')
.then(outputFunction);
Upvotes: 1
Reputation: 355
Make sure that your promisified functions are OK, this should also work:
var elements = ["one", "two", "three"]
var container = document.querySelector('.results')
function promisifiedFunc1(arrayElement) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('input to the next func ' + arrayElement)
}, 1000)
})
}
function promisifiedFunc2(inputFromPreviousFunc) {
return new Promise(function(resolve, reject) {
container.innerHTML += "<br>" + inputFromPreviousFunc
setTimeout(function() {
resolve('some filter')
}, 1000)
})
}
Promise.map(elements, function(one) {
return promisifiedFunc1(one).then(promisifiedFunc2);
})
.filter(function(res2) {
return res2 === 'some filter';
})
.then(function(allResults) {
console.log(allResults);
container.innerHTML += "<br>All Done!";
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.5.0/bluebird.min.js"></script>
<div class="results"></div>
Promise.map
allows you to map any array into an array of promises and generate a new promise that will be resolved once all these promises are resolved. Within the mapping function you can chain the two promises.
Upvotes: 1
Reputation: 22050
I assumed this would already have an answer here on SO, but apparently it doesn't (or if it does a couple of quick searches didn't find it).
You want a structure like this:
let filteredResults = Promise.all(arr.map(x => promisifiedFn1(x)))
.then(xs => xs.map(result1 => promisifiedFn2(result1)))
.then(ys => ys.filter(someFilteringFn));
Promise.all
can be thought of as turning a container inside-out: you give it an array of Promises (by mapping your promise-returning function over an array of inputs) and it gives you a Promise of an array of the results which you then treat like any other array.
So xs
is an array of the results of the first function mapped over the inputs once it all resolves. ys
is the second. I'm not sure what bluebird's Promise.map
does but you could possibly combine the first two steps in my code with it.
Since your doing a full processing of each input before deciding whether or not to keep the result, there's no penalty to simply processing the inputs with the two async steps and then filtering the resulting array once everything resolves.
Upvotes: 1