Reputation: 139028
In Scala I can take a list of values, map a future-returning function across them, and get back a future that will collect the values of those futures into a list (or fail with the first error). More concretely:
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
def doSomething(i: Int): Future[Int] = future(i + 1) // Not really doing much.
val incremented = Future.traverse(List(1, 2, 3))(doSomething)
In this case the result will just be the incremented list:
scala> incremented.onSuccess { case xs => println(xs) }
List(2, 3, 4)
I could alternatively create a list of futures and then turn them into a future containing the same result:
val incremented = Future.sequence(List(1, 2, 3).map(doSomething))
This will give me the same thing, but it creates an extra intermediate collection and is a little more noisy.
I want to do something like this with promises in Q, and it looks like Q.all
is more or less sequence
:
function doSomething(i) { return Q.fcall(function () { return i + 1; }); }
Q.all([1, 2, 3].map(doSomething)).then(function (xs) { console.log(xs) })
Is there a way for me to write a more traverse
-like version? It's such a basic operation that it seems like there must be a way to do it, but this is my first afternoon with Q and I'm still working through all the overloads of fcall
and friends.
Upvotes: 4
Views: 336
Reputation: 11274
Not directly an answer to your question, but AngularJS uses an extremely reduced version of Q ($q), so there you definitely have to implement this behavior yourself.
Here's one approach:
var traverse = function(fn /*values*/) {
var values = _.rest(arguments);
var promises = _.map(values, fn);
return $q.all(promises);
};
Full example: http://plnkr.co/edit/PGp7QbQYMjOknJwSEn8E
Or with separate parameter lists as in Scala:
var traverse = function(/*values*/) {
var values = arguments;
return function(fn) {
var promises = _.map(values, fn);
return $q.all(promises);
}
};
Full example: http://plnkr.co/edit/pWoGGaZobbx61tAmUWr9?p=preview
Upvotes: 1
Reputation: 6595
You can use Promise Chaining + Static values (instead of promises) for methods and do something like:
Q.all([1,2,3])
.then(function(xs) {
return _(xs).map(doSomething)
})
.then(function(xs) {
console.log(xs);
});
If you want a traverse function like that one, you can easily implement it yourself
Hope it helps!
Upvotes: 0