Again and again I am struggling when a function relies on some future results. This usually boils down to a result like Future[Seq[Future[MyObject]]]
To get rid of that
The Akka documentation has a nice overview on how to deal with a compositions of futures. In general, it outlines four methods in scala.concurrent.Future that can be used to reduce a composition of futures into a single Future instance:
Future.sequence
Future.traverse
Future.fold
Future.reduce
Two handy functions on the Future companion object you should know could help here, the first, and easier to wrap your head around is Future.sequence
. It takes a sequnce of futures and returns a Future of a sequence. If are ending up with a Future[Seq[Future[MyObject]]]
, lets call that result
. then you can change this to a Future[Future[Seq[MyObject]]]
with result.map(Future.sequence(_))
Then to collapse a Future[Future[X]]
for any X, you can run "result.flatMap(identity)", in fact, you can do this for any M[M[X]]
to create a M[X]
as long as M
has flatMap
.
Another useful function here is Future.traverse
. It is basically the result of taking a Seq[A]
, mapping it to a Seq[Future[B]]
, then running Future.sequence to get a Future[Seq[B]]
So in your example, you'd have:
ideas.map{ Future.traverse(_){ idea =>
/*something that returns a Future[JsObject]*/
} }.flatMap(identity)
However, many times when you are running flatMap(identity), you could be turning a map into a flatMap, and this is the case here:
ideas.flatMap{ Future.traverse(_) { idea =>
/*something that returns a Future[JsOjbect]*/
} }