如何解决Scala异步行为

时间:2017-08-23 13:41:22

标签: scala playframework

在我的后端控制器功能中,我有以下代码:

  def getContentComponents = Action.async {
    contentComponentDTO.list().map { contentComponentsFuture =>
      contentComponentsFuture.foreach(contentComponentFuture =>
        contentComponentFuture.typeOf match {
          case 5 => contentComponentDTO.getContentComponentText(contentComponentFuture.id.get).map(text => {
            contentComponentFuture.text = text.text
            println(contentComponentFuture.text)
          })

        }
      )
      Ok(Json.toJson(contentComponentsFuture))
    }
  }

问题是,在上述内容完成之前调用了OK()。是否有一种聪明的方式可以等到foreach完成?

感谢

这是两个有不同问题的不同问题!这就是两个问题看起来相似的原因

1 个答案:

答案 0 :(得分:0)

您可以采取两种方法,但在此之前,让我们回顾一下您要做的事情。

  1. 你有一个项目列表contentComponentsFuture,我假设从数据库中检索,这就是为什么你有一个未来。
  2. 现在你的contentComponentsFuture是一个可变变量(我强烈建议不要使用,坚持不可变数据)有一个你需要更新的文本字段。 现在Ok()之前的所有代码块将返回未来,因为它正在处理未来的列表。因此,最简单的解决方案是在未来绘制地图并返回结果。未来的地图只是一个onComplete函数,一旦未来得到解决就会触发。所以代码看起来像:

    def getContentComponents = Action.async {
    val futureResult = contentComponentDTO.list().map { contentComponentsFuture =>
      contentComponentsFuture.map(contentComponentFuture =>
        contentComponentFuture.typeOf match {
          case 5 => contentComponentDTO.getContentComponentText(contentComponentFuture.id.get).map(text => {
            contentComponentFuture.text = text.text
            contentComponentFuture
          })
        }
      )
    }
        futureResult.map(result => {
    Future.sequence(result).map(t => Ok(Json.toJson(t))
    

    }))     }

  3. 另一个选项是使用scala asycn库:https://github.com/scala/scala-async 它提供了一个方便的包装器,因此您不需要显式地映射未来,上面与scala异步库相同的代码将如下所示:

    def getContentComponents = Action.async {
        Async.async {
        val result = Async.await(contentComponentDTO.list().map { contentComponentsFuture =>
          contentComponentsFuture.map(contentComponentFuture =>
            contentComponentFuture.typeOf match {
              case 5 => contentComponentDTO.getContentComponentText(contentComponentFuture.id.get).map(text => {
                contentComponentFuture.text = text.text
                contentComponentFuture
              })
            }
          )
        })
    
        Ok(Json.toJson(result))
      }
      }