Снова и снова я борюсь, когда функция опирается на некоторые будущие результаты. Это обычно сводится к результату, например 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))
}
})
}
Этот код работает, но для меня он выглядит довольно взломанным. Два вызова карты - еще одна ошибка. Я потратил часы, пытаясь понять, как сохранить это полностью асинхронным и вернуть простой будущий Seq. Как это можно решить, используя лучшие методы Play2?
Edit Чтобы сделать usecase более понятным:
У меня есть объект A от mongodb (reactivemongo) и хочу добавить информацию, поступающую с другого вызова в mongodb getShortInfo
. Это классический случай "получить пользователя для этого сообщения", который будет разрешен с присоединением к РСУБД.
getShortInfo
, естественно, создаст будущее из-за вызова в db.
Чтобы уменьшить вложенность в 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, возвращайте результат к асинхронному действию таким образом, чтобы не возникало никаких ситуаций блокировки.