的问题是,一旦你开始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")
}
如果你有几个未来的呼叫,其中每一个从其他未来需要的结果,您可以使用对于理解避免地图地狱。例如,这里是一个小更复杂的例子:
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
}
在每个值是未来,但吼叫我们就可以访问自己的价值,在的对,你用得到目的,以纪念什么需要被退回。
其他示例可以是该控制器调用(忽略shilouete部分,是一种认证库,简单地认为返回类型作为未来[结果]):
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
将Seq[Future[Any]]
转换为Future[Seq[Any]]
和其他函数,以帮助您以不同方式处理期货。