当一个函数依赖于一些未来的结果时,我一次又一次地陷入困境。
这通常可以归结为像 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))
}
})
}
这段代码可以工作,但对我来说它看起来很老套。两次地图调用是另一个缺陷。
我花了几个小时试图弄清楚如何保持完全异步并返回一个简单的 future Seq。如何使用 Play2 最佳实践来解决这个问题?
Edit为了使用例更加清晰:
我有一个来自 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))
}
}
所以我认为返回一个Seq[Future[X]]
来自 findAll 不会带来更好的性能,因为无论如何我都必须等待结果。它是否正确?
简而言之,用例:
进行返回序列的 Future 调用,使用结果的每个元素创建另一个 Future 调用,以不应该发生阻塞情况的方式将结果返回到异步操作。