Travis Brown
Travis Brown

Reputation: 139028

Traversing promises in Q

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

Answers (2)

Marius Soutier
Marius Soutier

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

mgonto
mgonto

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

Related Questions