scala - 摆脱 Scala Future 嵌套

标签 scala playframework-2.0 future

当一个函数依赖于一些 future 的结果时,我一次又一次地陷入困境。 这通常可以归结为像 Future[Seq[Future[MyObject]]] 这样的结果

为了摆脱这个问题,我现在在辅助函数中使用 Await 来获取非 future 对象并减少嵌套。

看起来像这样

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))
      }
    })
}

这段代码可以工作,但对我来说它看起来很老套。两次 map 调用是另一个缺陷。 我花了几个小时试图弄清楚如何保持完全异步并返回一个简单的 future Seq。如何使用 Play2 最佳实践来解决这个问题?

编辑 为了使用例更加清晰:

我有一个来自 mongodb (reactivemongo) 的对象 A,并且想要添加来自对 mongodb getShortInfo 的另一个调用的信息。这是一个经典的“获取此帖子的用户”案例,可以通过 RDBMS 中的联接来解决。 由于调用了数据库,getShortInfo自然会产生一个Future。 为了减少 findAll 中的嵌套,我使用了 Await()。这是个好主意吗?

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 调用,以不应该发生阻塞情况的方式将结果返回到异步操作。

最佳答案

您应该知道的 Future 伴随对象上的两个方便的函数可以在这里提供帮助,第一个也是更容易理解的函数是 Future.sequence。它需要一个 future 序列并返回一个序列的 Future。如果最终得到 Future[Seq[Future[MyObject]]],我们就调用该结果。那么你可以将其更改为 Future[Future[Seq[MyObject]]]result.map(Future.sequence(_))

然后,要折叠任何 X 的 Future[Future[X]],您可以运行“result.flatMap(identity)”,事实上,您可以对任何 M 执行此操作[M[X]] 创建一个 M[X],只要 M 具有 flatMap

这里另一个有用的函数是Future.traverse。它基本上是采用 Seq[A],将其映射到 Seq[Future[B]],然后运行 ​​Future.sequence 来获取 的结果Future[Seq[B]] 因此,在您的示例中,您将:

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

但是,很多时候,当您运行 flatMap(identity) 时,您可能会将 map 转换为 flatMap,这里就是这种情况:

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

关于scala - 摆脱 Scala Future 嵌套,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20276872/

相关文章:

scala - 如何使用 Playframework 2.0 实现多元化和其他扩展

rust - 如何将异步/标准库 future 转换为 futures 0.1?

templates - 在play2中,scala模板中的区分大小写不起作用

python - 在 Python 中设计异步 API

dart - StreamBuilder 限制

macos - 让 Scala 解释器工作

java - 通过 Java 创建 Kafka 主题时出错

scala - 我需要更改什么才能使 Scala 2.13 MultiDict 用作​​ 2.12 的 MultiMap 的直接替代品?

scala - 如何在 Scala 中向 Map 添加可选条目?

scala - Play 框架 2.x Scala 模板中的内联变量