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
processFilealways runs in aFutureeven 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))
}