2017-09-15 2 views
0

Je suis nouveau pour jouer framework (2.6.x) et Scala. J'ai une fonction qui renvoie un Future [JsValue]. Comment puis-je utiliser Future [JsValue] dans une fonction ultérieure?Utilisation de Future [JsValue] dans une fonction suivante Framework de lecture 2.6x

def getInfo(): Future[JsValue] ={} 

La fonction suivante utilisera une valeur de JsValue pour calculer quelque chose.

Quelque part au milieu, je dois extraire une valeur de la réponse json. val currentWeight = (jsValue \ "weight").as[String].toDouble

def doubleAmounts(currentWeight: Double): Double = { 
    currentWeight*2.0 
} 

Quelle est la bonne façon de gérer un avenir ici? Devrais-je utiliser une carte ou onComplete pour obtenir le weight de json?

J'ai essayé mais cela résout seulement après que j'ai déjà appelé doubleAmounts().

val weight = getInfo() map { response => 
    if (response.toString().length > 0) (response \ "weight").as[String]) 
    else throw new Exception("didn't get response") 
} 

Répondre

0

Le problème est, une fois que vous commencez à parler à Futures, vous devez continuer à parler dans Futures, l'idée est que le même serveur traitera tout ce temps d'attente et les changements de contexte, donc jouer l'auto peut gérer votre promets qu'à un certain piont, vous retournerez un résultat. Ainsi, au lieu d'appeler des fonctions dans vos contrôleurs qui renvoient un Any, le jeu peut gérer Future[Any].

val weight: Future[String] = getInfo() map { response => 
    if (response.toString().length > 0) (response \ "weight").as[String]) 
    else throw new Exception("didn't get response") 
} 

Si vous avez plusieurs appels futurs, où chacun a besoin le résultat d'un autre avenir, vous pouvez utiliser Pour une meilleure compréhension pour éviter l'enfer de la carte. Par exemple, voici un petit exemple plus complexe:

def processSync(databaseServer: DatabaseServer, databaseIdentity: DatabaseIdentity): Future[String] = { 
    val info = for { 
     catalogs <- databaseSyncService.getCatalogs(databaseServer.address, databaseServer.port, databaseIdentity.login, databaseIdentity.password) 
     clubbers <- getClubbers(databaseServer.id) 
     ignoredCatalogs <- ignoredCatalogService.get(databaseServer.id) 
    } yield (catalogs, clubbers, ignoredCatalogs) 
    val result = info.map{ 
     case(catalogs, clubbers, ignoredCatalogs) => { 
     val currentCatalogs = (clubbers.map(clubber => 
      Seq(Some(clubber.mainSchema), clubber.archiveSchema, clubber.blacklistSchema, clubber.logsSchema).flatten 
     ).flatten ++ ignoredCatalogs).toSet 
     val serverCatalogs = catalogs.toSet 
     if(currentCatalogs == serverCatalogs) { 
      "synchronized" 
     } else { 
      "outOfSync" 
     } 
     } 
    }.recover{ 
     case sqlE: SQLServerException =>{ 
     logger.error(s"Conection error with ${databaseServer.name}", sqlE) 
     "connectionError" 
     } 
    } 
    for{ 
     realResult <- result 
     _ <- databaseServerRepo.updateSync(databaseServer.id, realResult) 
    } yield realResult 
    } 

Chaque valeur dans le pour un avenir, mais ci-dessous, nous pouvons accéder à leur valeur, à la fin du pour, vous utilisez le rendement pour marquer ce besoin de être retourné.

Autre exemple pourrait être cet appel du contrôleur (ignorer la partie shilouete, est une bibliothèque d'authentification, pensez simplement du type de retour comme un avenir [Résultat]):

def sync(id: Int) = silhouette.SecuredAction.async { implicit request: SecuredRequest[DefaultEnv, AnyContent] => 
    val actions = for { 
     (server, identity) <- databaseServerService.getWithIdentity(id) 
     databaseCatalogs <- databaseSyncService.getCatalogs(server.address, server.port, identity.login, identity.password) 
     ignoredCatalogs <- ignoredCatalogService.get(id) 
     clubberIntegrations <- clubberIntegrationService.getClubbersListOrAutoFill(id, databaseCatalogs, ignoredCatalogs.map(_.name)) 
    } yield Future.successful { 
     val catalogs = databaseCatalogs.map { x => 
     val ignoredCatalogNotes = ignoredCatalogs.filter(_.name == x).map(_.note).headOption 
     DatabaseCatalog(x, ignoredCatalogNotes.getOrElse(""), ignoredCatalogNotes.isDefined) 
     } 
     Ok(web.databaseserver.views.html.databaseServerSync(request.identity, server, DatabaseServerForSync(clubberIntegrations, catalogs))) 
    } 
    actions.recover { 
     case _: SQLServerException => { 
     databaseServerService.getName(id).map(x => { 
      Redirect(web.databaseserver.controllers.routes.DatabaseServerController.list()) 
      .flashing("error" -> Messages("databaseSync.couldNotConnect", x)) 
     }) 
     } 
    }.flatMap(x => x) 
    } 

, j'ai oublié de mentionner également, Si vous avez besoin de gérer une fonction qui utilise un avenir et d'autres ne pas, vous pouvez transformer ce dernier avec Future.successful, il est également Future.sequence pour convertir un Seq[Future[Any]] en Future[Seq[Any]] et d'autres fonctions pour vous aider à gérer les futurs de différentes manières.