Снова и снова я борюсь, когда функция зависит от некоторых будущих результатов. Это обычно сводится к следующему результату, как Future [Seq [Future [MyObject]]]Избавьтесь от Scala Будущее гнездования
Чтобы избавиться от этого, теперь я использую 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?
Редактировать Чтобы сделать UseCase более ясным:
У меня есть объект А из MongoDB (reactivemongo) и хотите добавить информацию, поступающую от другого вызова MongoDB getShortInfo
. Это классический случай «получить пользователя для этого сообщения», который будет разрешен с присоединением к РСУБД. getShortInfo
, естественно, создавал бы Будущее из-за вызова на БД. Чтобы уменьшить вложенность в пределах findAll
Я использовал Await(). Это хорошая идея?
findAll
вызывается из асинхронного игрового действия, преобразованного в 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, возвращайте результат асинхронному действию таким образом, чтобы не возникало никаких ситуаций блокировки.
К сожалению , Я не понимаю, на что вопрос. Если вы просто хотите фильтровать или обрабатывать значения завернутого Seq в будущем, то ваше решение кажется прекрасным. Нет ничего плохого в том, что у вас есть два вызова карты; что является нормальным и необходимым, поскольку первая карта находится над Будущим, а вторая - над Seq. Я не вижу необходимости в Await here; вы говорите, что это уже происходит внутри UserDao.getShortInfo? –
Итак, я думаю, что ваш вопрос: если вы не использовали Await внутри UserDao.getShortInfo, тогда он бы создал Future [JsObject]. и выход этого FindAll был бы Future [Seq [Future [Idea]]], который не то, что вы хотите. Тогда возникает вопрос, чего вы хотите. Вы уверены, что вам понадобится Future [Seq [Idea]], который может разрешить только один раз, когда все элементы были обработаны? Возможно, вы предпочтете Seq [Future [Idea]], поскольку элементы, как представляется, обрабатываются независимо в любом случае? –
Тем временем я узнал, что всегда можно избавиться от всех операций блокировки. При использовании некоторых методов внутри этих ответов и сопоставления операций над операциями, которые возвращают будущее, вам больше не понадобится использовать ожидание. – DanielKhan