代码之家  ›  专栏  ›  技术社区  ›  Felix

Scala Play:如何等到将来完成后再将OK结果返回到前端

  •  0
  • Felix  · 技术社区  · 6 年前

    在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

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

    2 回复  |  直到 6 年前
        1
  •  4
  •   Andrey Tyukin    6 年前

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

    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 此处)是在执行该行为之前确定完成该操作的原因,以便 列表PTMS 之前进行了全面评估 好啊 已构造。

        2
  •  2
  •   James Whiteley    6 年前

    为了等到未来完成,最常见的做法是做以下两件事之一:

    使用a进行理解,在 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