在同一个Action.async Scala Play中调用2个Futures

时间:2015-03-26 21:48:36

标签: scala playframework future

我是Scala的新手:(那说,我正在与Play框架Action.async和Future电话进行斗争。

我想在同一个动作中调用2个期货,等到他们都计算在我的视图中发送结果。

以下是代码:

    def showPageWithTags(category: String) = Action.async {
        val page = PageDAO.findOne(Json.obj("category" -> category)).map {
          case Some(page) => {
            page.content = page.content.byteArrayToString
          }
        }
        val futureTags = ArticleDAO.listTags
        Ok(views.html.web.pages.show(page, futureTags))
   }

使用这个定义的函数:

def findOne(id: String): Future[Option[PageModel]]

def listTags: Future[List[String]] 

我收到了这个错误:

[error]  found   : Some[A]
[error]  required: models.PageModel
[error]         case Some(page) => {
[error]              ^
.../...
[error]  found   : None.type
[error]  required: models.PageModel
[error]         case None => {
[error]              ^
.../...
[error]  found   : Option[Nothing]
[error]  required: scala.concurrent.Future[play.api.mvc.Result]
[error]       optionPage.map {
[error]                      ^
.../...
[error]  found   : scala.concurrent.Future[Unit]
[error]  required: models.PageModel
[error]         Ok(views.html.web.pages.show(optionPage, futureTags))
[error]                                      ^
.../...
[error]  found   : scala.concurrent.Future[List[String]]
[error]  required: List[String]
[error]         Ok(views.html.web.pages.show(optionPage, futureTags))
[error]                                                  ^

我已尝试使用map,for / yield,foreach来处理Option和Future,但总会有一个错误仍然存​​在。

然而,在我添加" Tag"之前,未来的一个电话工作正常。功能:

  def showPage(category: String) = Action.async {
    PageDAO.findOne(Json.obj("category" -> category)).map {
      case Some(page) => {
        page.content = page.content.byteArrayToString
        Ok(views.html.web.pages.show(page))
      }
      case None => {
        NotFound
      }
    }
  }

如何在同一操作中调用2个期货并等到他们都计算通过Ok()将它们传递到我的页面视图?

非常感谢任何澄清!

3 个答案:

答案 0 :(得分:3)

您需要mapflatMap Future s才能异步访问其结果。 Action.async需要Future[Result],因此您必须将Future映射到该def showPageWithTags(category: String) = Action.async { val page = PageDAO.findOne(Json.obj("category" -> category)).map { case Some(page) => { page.content.byteArrayToString } } val futureTags = ArticleDAO.listTags page.flatMap { page => futureTags.map { tags => Ok(views.html.web.pages.show(page, tags)) } } } 。这是一个简单的方法:

flatMap

或者你可以使用for-comprehension来清理它,这是map / def showPageWithTags(category: String) = Action.async { for { pageOpt <- PageDAO.findOne(Json.obj("category" -> category)) .map(_.map(_.content.byteArrayToString)) tags <- ArticleDAO.listTags } yield { pageOpt.map { page => Ok(views.html.web.pages.show(page, tags)) } getOrElse { NotFound } } } 的语法糖。

map

我还冒昧地简化了findOne {{1}}结果中的{{1}}。

答案 1 :(得分:2)

您可以使用flatMap的{​​{1}}方法。

  

Future方法采用将值映射到新的未来flatMap的函数,然后返回在g完成后完成的未来。

(来自http://docs.scala-lang.org/overviews/core/futures.html

所以也许试试:

g

答案 2 :(得分:0)

你可以这样试试。

def showPageWithTags(category: String) = Action.async {

   for{
       pOpt <- PageDAO.findOne(Json.obj("category" -> category))
      futureTags <- ArticleDAO.listTags
      } yield{
          pOpt match {
           case Some(x)=> Ok(views.html.web.pages.show(x.content.byteArrayToString, futureTags))
           case _=> NotFound
                     }              
            }         
}