当前位置: 首页 > 知识库问答 >
问题:

摆脱Scala未来嵌套

白云
2023-03-14

当一个函数依赖于一些未来的结果时,我一次又一次地挣扎。这通常归结为一个类似于Future[Seq[Future[MyObject]]的结果

为了摆脱这种情况,我现在在辅助函数中使用Aetc来获取一个非未来对象并减少嵌套。

它看起来像这样

def findAll(page: Int, perPage: Int): Future[Seq[Idea]] = {
    val ideas: Future[Seq[Idea]] = collection.find(Json.obj())
    // [...]

    ideas.map(_.map { // UGLY?
      idea => {
        // THIS RETURNED A Future[JsObject] before
        val shortInfo: JsObject = UserDao.getShortInfo(idea.user_id)
        idea.copy(user_data = Some(shortInfo))
      }
    })
}

这段代码有效,但对我来说,它看起来很笨拙。这两个映射调用是另一个缺陷。我花了几个小时试图弄清楚如何保持完全异步并返回一个简单的未来Seq。如何使用 Play2 最佳实践解决此问题?

编辑为了使用法更清楚:

我有一个来自mongodb(reactivemongo)的对象A,并且想要添加来自mongodb getShortInfo的另一个调用的信息。这是一个经典的“为这篇文章获取用户”的情况,可以通过加入RDBMS来解决。getShortInfo 自然会产生一个 Future,因为调用了 db。为了减少 findAll 中的嵌套,我使用了 Await()。这是个好主意吗?

< code>findAll从异步Play动作中调用,转换成Json并通过网络发送。

def getIdeas(page: Int, perPage: Int) = Action.async {

  for {
    count <- IdeaDao.count
    ideas <- IdeaDao.findAll(page, perPage)
  } yield {
    Ok(Json.toJson(ideas))
  }
}    

所以我认为从findAll返回Seq[Future[X]]不会带来更好的性能,因为我无论如何都必须等待结果。这是正确的吗?

简而言之:获取返回序列的 Future 调用,使用结果的每个元素创建另一个 Future 调用,以一种不会发生阻塞情况的方式将结果返回到异步操作。

共有2个答案

萧萧迟
2023-03-14

Akka文档对如何处理期货组合有很好的概述。一般来说,它概述了scala.concurrent中的四种方法。可用于将期货组合缩减为单个期货实例的期货:

  • 未来。序列
  • 未来。遍历
  • 未来。折叠
  • 未来。减少
闾丘山
2023-03-14

您应该知道,Future 伴随对象上的两个方便的功能可以在这里提供帮助,第一个,也是更容易绕开头脑的函数是 Future.sequence。它需要一个期货的序列,并返回一个序列的未来。如果以一个未来[Seq[Future[MyObject]]]结束,让我们调用该结果。然后你可以用 result.map(Future.sequence(_)) 将其更改为 Future[Future[Seq[MyObject]]]

然后,要为任何X折叠<code>未来[Future[X],您可以运行“result.flatMap(identity)”,事实上,您可以为任何<code>M[M[X].执行此操作,以创建<code>M[X]。

另一个有用的函数是<code>Future.traverse</code>。它基本上是取一个序列[a],将其映射到一个序列[Future[B]],然后运行Future的结果。序列以获得一个未来[Seq[B]],因此在您的示例中,您有:

ideas.map{ Future.traverse(_){ idea =>
    /*something that returns a Future[JsObject]*/
} }.flatMap(identity)

但是,很多时候,当您运行平面图(身份)时,您可能会将地图转换为平面图,情况如下:

ideas.flatMap{ Future.traverse(_) { idea =>
    /*something that returns a Future[JsOjbect]*/
} }
 类似资料:
  • 我有JavaWebService代码在我的eclipse。我使用了@WebService@Webmethod,@XmlElements,@XmlType,@XmlAccessorType 现在我正在使用cxf框架中的java2ws命令生成wsdl。这是命令 我的wsdl文件包含agr0作为我不想要的名称,因为当我将其导入SoapUI时。它正在字段周围添加标记。 下面是带有arg0的wsdl部分 下

  • 问题内容: 在我的JS中,我需要使用AJAX获取3个文件的内容,然后执行一些代码。这导致嵌套异步函数的外观看起来很奇怪。同样在我使用异步功能的任何时候,都会出现这种丑陋的嵌套。 当我真的只想等待它们完成时,如何避免嵌套函数?(如果有帮助,我正在使用jQuery) 问题答案: 这有几种使用和不使用延迟的不同技术。在所有情况下,都会启动所有ajax调用,然后一段代码跟踪所有ajax调用何时完成,并在调

  • 问题内容: 我正在使用Apache Derby嵌入式数据库在Maven项目中进行单元测试。不幸的是,每当运行测试时,我最终都会在项目根目录中找到该文件。数据库本身是在目录()中创建的,因此这不是问题。在查阅参考指南之后, 我尝试在JDBC url()上设置参数,但这似乎是针对其他日志的,因此仍然会出现。 任何帮助深表感谢。 问题答案: 您可以通过创建以下类来摆脱文件 并设置JVM系统属性,例如,使

  • 在这段代码中,我从\u RETURN\u VALUE得到了\u SOME\u PATH\u上的

  • 问题内容: 到目前为止,给我带来了很多麻烦,所以我想摆脱它。尽管spring框架文档清楚地说明了应该做的事情,但实际上 并没有摘要列表。 所以我一直坚持删除并得到错误 -在名称为的中找不到带有请求的映射 对于所有应该由控制器类解决的Url(在这种情况下:)。有什么建议可以让我了解更多信息吗?我非常想知道到底由代表什么标签。 问题答案: 你可以用来自定义定义的每个bean 。现在,javadocs详

  • 问题内容: 到现在为止,给我造成了很多麻烦,所以我想摆脱它。尽管spring框架文档清楚地说明了应该做的事情,但实际上 并没有摘要列表。 所以我坚持删除并现在得到错误 WARN osweb.servlet.PageNotFound-在DispatcherServlet中,名称为’workoutsensor’的URI [/ webapp / trainees]的HTTP请求未找到映射 对于所有应该由