加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

摆脱Scala Future嵌套

发布时间:2020-12-16 09:29:25 所属栏目:安全 来源:网络整理
导读:当函数依赖于未来的某些结果时,我一次又一次地挣扎. 这通常归结为像Future [Seq [Future [MyObject]]]这样的结果 为了摆脱这一点,我现在在辅助函数中使用Await来获取非未来对象并减少嵌套. 看起来像这样 def findAll(page: Int,perPage: Int): Future[Seq[Id
当函数依赖于未来的某些结果时,我一次又一次地挣扎.
这通常归结为像Future [Seq [Future [MyObject]]]这样的结果

为了摆脱这一点,我现在在辅助函数中使用Await来获取非未来对象并减少嵌套.

看起来像这样

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

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

编辑
为了使用例更清晰:

我有一个来自mongodb(reactivemongo)的对象A,并希望将来自另一个调用的信息添加到mongodb getShortInfo.这是一个经典的“获得此帖子的用户”案例,可以通过加入RDBMS来解决.
由于调用db,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调用返回一个Sequence,使用结果的每个元素创建另一个Future调用,以不会发生阻塞情况的方式将结果返回到异步操作.

解决方法

你应该知道的Future伴侣对象上的两个方便的函数可以帮到这里,第一个,更容易包围你的是Future.sequence.它需要一个未来的序列并返回一个序列的未来.如果以Future [Seq [Future [MyObject]]]结束,我们可以调用该结果.然后你可以用result.map(Future.sequence(_))将它改为Future [Future [Seq [MyObject]]]

然后为任何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(标识)时,您可能会将地图转换为flatMap,这就是这种情况:

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读