【发布时间】:2014-04-24 01:25:33
【问题描述】:
场景:
我有两个不同的 Api 调用(通过网络)。 ApiCall1,ApiCall2。最终 ApiCall1 将返回一个 Option[Catalogue] 而 ApiCall2 将返回一个 Seq[Catalogue]
然后我需要使用这两个并构建一个 FrontPage 对象。在 FrontPage 对象的实例化过程中,它创建了一个 Seq[NewProducts]。每次它创建一个 NewProduct 时,NewProduct 还必须在 Future 中通过 Web 调用一个 MongoDB。在将 FrontPage 对象交给视图之前,每个 Future 都必须完成。
这是 FrontPage 类的代码:
case class FrontPage(maybeCat1: Option[Catalogue], maybeCat2: Seq[Catalogue]) {
val newProducts:Seq[NewProduct] = {
maybeCat2.map( { cat =>
NewProduct(cat)
})
}
}
到目前为止,NewProduct 类的代码如下:
case class NewProduct(cat:Catalogue) {
val indivProduct:Option[IndivProduct] = {
// ???
// This next line goes out to Mongo and returns a Future[List[JsObject]]
val indiv:Future[List[JsObject]] = MongoFetch.getIndivProduct(cat)
//need to strip out the 'Future', wait for it to return?
val listJS = indiv .. ???? // <-- need just the List[JsObject]]
return IndivProduct(listJs) // <-- constructs a new Option[IndivProduct]
}
}
这是目前控制器的代码:
def landing() = Action.async {
for {
catalogue1 <- models.Granite.getCatalogue("front-page") // <- ApiCall1
catalogue2 <- models.Granite.getCatalogue("tags") // <- ApiCall2
} yield {
//??? How to now build the FrontPage object
// surely it also depends on the future?
val fp = FrontPage(catalogue1, catalogue2)
Ok(views.html.frontpage.landing(fp)) // <- at this point all futures must have returned.
}
}
我真的希望能够将一个漂亮整洁的 FrontPage 对象传递给视图(以及设计师),并在其上定义一组非常简单的函数,供他们使用。所有的期货都必须回归。 Catalogue1 和 Catalogue2 不依赖于任何东西,甚至不依赖于彼此。在 FrontPage 对象中创建 Seq[NewProducts] 取决于它们都已返回。然后我不能将 FrontPage 对象传递给视图,直到它从 Mongo 返回 NewProducts。
这种复杂程度超出了我的习惯。我对何时何地使用 for/yield 理解感到困惑。恐怕这会以某种方式阻塞,因为 Futures 太嵌入在案例类中,在案例类中。控制器的最顶层封装在 Async 中,那么这是否意味着该 Async 调用中的所有 Future 都将是非阻塞的?
【问题讨论】:
-
你能避免在你的构造函数中做这个工作吗?即,将其移至返回
Future[NewProduct]? 的构造函数方法 -
@TravisBrown - 问题是我真的想将一个完整的、完全完整的 FrontPage 传递给视图。