Scala Play:如何在OK结果返回前端之前等待将来完成

时间:2018-04-06 15:07:12

标签: scala playframework

在我的playframework应用程序中,我想等到我的未来完成并将其返回到视图中。

我的代码如下:

 def getContentComponentUsageSearch: Action[AnyContent] = Action.async { implicit request =>
    println(request.body.asJson)
    request.body.asJson.map(_.validate[StepIds] match {
      case JsSuccess(stepIds, _) =>

        println("VALIDE SUCCESS -------------------------------")


        val fList: List[Seq[Future[ProcessTemplatesModel]]] = List() :+ stepIds.s.map(s => {
          processTemplateDTO.getProcessStepTemplate(s.processStep_id).flatMap(stepTemplate => {
            processTemplateDTO.getProcessTemplate(stepTemplate.get.processTemplate_id.get).map(a => {
              a.get
            })
          })
        })


        fList.map(u => {
          val a: Seq[Future[ProcessTemplatesModel]] = u

          Future.sequence(a).map(s => {
            println(s)
          })
        })


        Future.successful(Ok(Json.obj("id" -> "")))

      case JsError(_) =>
        println("NOT VALID -------------------------------")
        Future.successful(BadRequest("Process Template not create client"))
      case _ => Future.successful(BadRequest("Process Template create client"))
    }).getOrElse(Future.successful(BadRequest("Process Template create client")))
  }

pirntln(s)正在打印已完成的内容。但是我怎么能等到它完成然后再返回视图呢?

提前致谢

更新:

也尝试了这个:

  val process = for {

      fList: List[Seq[Future[ProcessTemplatesModel]]] <- List() :+ stepIds.s.map(s => {
        processTemplateDTO.getProcessStepTemplate(s.processStep_id).flatMap(stepTemplate => {
          processTemplateDTO.getProcessTemplate(stepTemplate.get.processTemplate_id.get).map(a => {
            a.get
          })
        })
      })

    } yield (fList)





    process.map({ case (fList) =>
      Ok(Json.obj(
        "processTemplate" -> fList
      ))
    })

然后我得到了这个:

enter image description here

更新: 我的问题是fList中的期货在返回OK结果之前没有完成

2 个答案:

答案 0 :(得分:4)

问题中的代码似乎不可编辑,因此这是一个未经测试的非常粗略的草图,希望为进一步搜索正确的解决方案提供足够的灵感:

def getContentComponentUsageSearch: = Action.async { implicit req =>
  req.body.asJson.map(_.validate[StepIds] match {
    case JsSuccess(stepIds, _) => {

      // Create list of futures
      val listFuts: List[Future[ProcessTemplatesModel]] = (stepIds.s.map(s => {
        processTemplateDTO.
          getProcessStepTemplate(s.processStep_id).
          flatMap{ stepTemplate => 
            processTemplateDTO.
              getProcessTemplate(stepTemplate.get.processTemplate_id.get).
              map(_.get)
          }
      })).toList

      // Sequence all the futures into a single future of list
      val futList = Future.sequence(listFuts)

      // Flat map this single future to the OK result
      for {
        listPTMs <- futList
      } yield {
        // Apparently some debug output? 
        listPTMs foreach printl

        Ok(Json.obj("id" -> ""))
      }
    }

    case JsError(_) => {
      println("NOT VALID -------------------------------")
      Future.successful(BadRequest("Process Template not create client"))
    }

    case _ => Future.successful(BadRequest("Process Template create client"))

  }).getOrElse(Future.successful(BadRequest("Process Template create client")))
}

如果我理解你的问题,你想要的是确保列表中的所有未来在你返回OK之前完成。因此,我首先创建了一个List[Future[...]]

  val listFuts: List[Future[ProcessTemplatesModel]] = // ...

然后我将所有的期货合并到一个列表的未来,只有在每个元素都完成时才会完成:

  // Sequence all the futures into a single future of list
  val futList = Future.sequence(listFuts)

然后我使用for - 理解来确保listPTMs在返回OK之前完成计算:

  // Flat map this single future to the OK result
  for {
    listPTMs <- futList
  } yield {
    // Apparently some debug output? 
    listPTMs foreach printl

    Ok(Json.obj("id" -> ""))
  }

for-yield(此处相当于map)确定了此前行为的完成情况,以便在listPTMs之前对OK进行全面评估是建造的。

答案 1 :(得分:3)

为了等到Future完成,最常见的是做两件事之一:

使用for-comprehension,在yield部分执行任何操作之前,会在幕后进行一系列映射和平面映射(有关更详细的说明,请参阅Andrey的注释)。一个简化的例子:

def index: Action[AnyContent] = Action.async {    
  val future1 = Future(1)
  val future2 = Future(2)

  for {
    f1 <- future1
    f2 <- future2
  } yield {
    println(s"$f1 + $f2 = ${f1 + f2}") // prints 3
    Ok(views.html.index("Home"))
  }
}

映射未来:

def index: Action[AnyContent] = Action.async {    
  val future1 = Future(1)

  future1.map{
    f1 =>
    println(s"$f1")
    Ok(views.html.index("Home"))
  }
}

如果有多个期货:

def index: Action[AnyContent] = Action.async {

  val future1 = Future(1)
  val future2 = Future(2)

  future1.flatMap{
    f1 =>
      future2.map {
        f2 =>
          println(s"$f1 + $f2 = ${f1 + f2}")
          Ok(views.html.index("Home"))
      }
    }
  }
}

当你有多个期货时,for-yield理解的论点变得更加强大,因为它更容易阅读。此外,您可能知道,但如果您使用期货,您可能需要关注进口:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global