Futures - carte vs flatmap
J'ai lu les docs sur map
et flatMap
et je comprends que flatMap
est utilisé pour une opération qui accepte un Future
paramètre et renvoie une autre Future
. Ce que je n'ai pas entièrement comprendre, c'est pourquoi je veux le faire. Prenez cet exemple:
- Utilisateur accède à mon webservice demandant de "faire des trucs"
- - Je télécharger un fichier (qui est lent)
- - Je traiter le fichier (qui est consommateur d'UC)
- Rendre le résultat
Je comprends que j'ai envie d'utiliser un avenir pour télécharger le fichier, mais j'ai deux options re de traitement:
val downloadFuture = Future { downloadFile }
val processFuture = downloadFuture map { processFile }
processFuture onSuccess { case r => renderResult(r) }
ou
val downloadFuture = Future { //download the file }
val processFuture = downloadFuture flatMap { Future { processFile } }
processFuture onSuccess { case r => renderResult(r) }
En ajoutant des instructions de débogage (Thread.currentThread().getId
) je vois que dans les deux cas de téléchargement, process
et render
se produire dans le même thread (à l'aide de ExecutionContext.Implicits.global
).
Aurais-je utiliser flatMap
simplement à découpler downloadFile
et processFile
et de s'assurer que processFile
s'exécute toujours dans un Future
même si elle n'a pas été cartographiés à partir de downloadFile
?
source d'informationauteur
Vous devez vous connecter pour publier un commentaire.
Oui, c'est correct.
Cependant la plupart du temps, vous ne l'utilisez
Future { ... }
directement, vous pouvez utiliser les fonctions (d'autres bibliothèques ou de votre propre) qui renvoie unFuture
.Imaginer les fonctions suivantes :
Vous pouvez utiliser
flatMap
de les combiner entre eux :Ou à l'aide d'une compréhension :
La plupart du temps vous ne les qualifierais pas de
onSuccess
(ouonComplete
). En utilisant l'une de ces fonctions, vous inscrire à une fonction de rappel qui sera exécutée lorsque leFuture
finitions.Si, dans notre exemple, vous voulez rendre le résultat du traitement d'un fichier, vous seriez de retour à quelque chose comme
Future[Result]
au lieu de l'appelerfutResult.onSuccess(renderResult)
. Dans le dernier cas, votre type de retour seraitUnit
de sorte que vous ne pouvez pas vraiment retourner quelque chose.En Jeu Cadre de ce qui pourrait ressembler à :
Si vous avez un avenir, disons,
Future[HttpResponse]
et que vous souhaitez spécifier de quoi faire avec ce résultat, quand il est prêt, comme écrire le corps d'un fichier, vous pouvez faire quelque chose commeresponseF.map(response => write(response.body)
. Toutefois, siwrite
est également une méthode asynchrone qui renvoie un futur, cemap
appel renvoie un type commeFuture[Future[Result]]
.Dans le code suivant:
stringF
est de typeFuture[Future[String]]
toutflatStringF
est de typeFuture[String]
. La plupart seraient d'accord, la seconde est plus utile. Plat de la Carte est donc utile pour la rédaction de plusieurs contrats à terme ensemble.Lorsque vous utilisez
for
interprétations avec des contrats à Terme, sous le capotflatMap
est utilisé ensemble avecmap
.Ce code rendement: 60.
Sous le capot, scala traduit ce à
C'est un exemple simple, où comment la flatMap travaille pour l'Option, cela peut aider à mieux comprendre, C'est en fait la composition n'est pas l'ajout d'un wrapper de nouveau.C'est ce que nous avons besoin.