I\'ve read the docs about map
and flatMap
and I understand that flatMap
is used for an operation that accepts a Future
pa
ensure that
processFile
always runs in aFuture
even if it was not mapped fromdownloadFile
?
Yes that is correct.
However most of the time you wouldn't use Future { ... }
directly, you would use functions (from other libraries or your own) which return a Future
.
Imagine the following functions :
def getFileNameFromDB{id: Int) : Future[String] = ???
def downloadFile(fileName: String) : Future[java.io.File] = ???
def processFile(file: java.io.File) : Future[ProcessResult] = ???
You could use flatMap
to combine them :
val futResult: Future[ProcessResult] =
getFileNameFromDB(1).flatMap( name =>
downloadFile(name).flatMap( file =>
processFile(file)
)
)
Or using a for comprehension :
val futResult: Future[ProcessResult] =
for {
name <- getFileNameFromDB(1)
file <- downloadFile(name)
result <- processFile(file)
} yield result
Most of the time you would not call onSuccess
(or onComplete
). By using one of these functions you register a callback function which will be executed when the Future
finishes.
If in our example you would like to render the result of the file processing, you would return something like Future[Result]
instead of calling futResult.onSuccess(renderResult)
. In the last case your return type would be Unit
, so you can not really return something.
In Play Framework this could look like :
def giveMeAFile(id: Int) = Action.async {
for {
name <- getFileNameFromDB(1)
file <- downloadFile(name)
processed <- processFile(file)
} yield Ok(processed.byteArray).as(processed.mimeType))
}