我是玩框架(2.6.x)和Scala的新手。我有一个返回Future [JsValue]的函数。如何在后续函数中使用Future [JsValue]?
def getInfo(): Future[JsValue] ={}
以下函数将使用JsValue中的值来计算某些内容。
在中间某处我必须从json响应中提取一个值。 val currentWeight = (jsValue \ "weight").as[String].toDouble
def doubleAmounts(currentWeight: Double): Double = {
currentWeight*2.0
}
这里处理未来的正确方法是什么?我应该使用map还是onComplete从json获取weight
?
我尝试了这个,但它只在我调用doubleAmounts()
后才解决。
val weight = getInfo() map { response =>
if (response.toString().length > 0) (response \ "weight").as[String])
else throw new Exception("didn't get response")
}
答案 0 :(得分:0)
问题是,一旦你开始在Futures
讲话,你需要继续在Futures
讲话,这个想法是同一个服务器将处理所有这些等待和上下文的变化,所以玩它自我可以处理你的承诺,在某些情况下,你会返回一个结果。
因此,不是在控制器中调用返回Any
的函数,而是可以处理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")
}
如果你有几个未来的电话,每个人都需要其他Future的结果,你可以使用 For comprehension 来避免地图地狱。例如,这是一个更复杂的例子:
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
}
for中的每个值都是未来,但是下面我们可以访问它们的值,在for的末尾,你使用yield来标记需要返回的内容。
其他示例可能是此控制器调用(忽略shilouete部分,是一个身份验证库,只需将返回类型视为Future [Result]):
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)
}
另外,我忘了提一下,如果你需要处理一个使用Future的函数而另一个函数没有,你可以使用Future.successful
转换后者,还有Future.sequence
来转换{ {1}}进入Seq[Future[Any]]
和其他功能,以帮助您以不同的方式处理未来。