Pozbądź się gniazdowania Scala Future
Raz po raz walczę, gdy funkcja opiera się na przyszłych wynikach. Zazwyczaj sprowadza się to do wyniku takiego jak Future [Seq [Future [MyObject]]]
Aby się tego pozbyć, teraz używam Await wewnątrz funkcji pomocniczej, aby uzyskać nie-przyszły obiekt i zmniejszyć zagnieżdżanie.
To wygląda tak
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))
}
})
}
Ten kod działa, ale dla mnie wygląda dość hacky. Dwa wywołania map to kolejna wada. Spędziłem godziny próbując dowiedzieć się, jak zachować to całkowicie asynchronicznie i zwrócić prosty przyszły Seq. Jak można to rozwiązać za pomocą najlepszych praktyk Play2?
Edytować Aby uczynić skrzynkę bardziej przejrzystą:
Mam obiekt A z mongodb (reactivemongo) i chcę dodać informacje pochodzące z innego wywołania do mongodbgetShortInfo
. Jest to klasyczny przypadek „pobierz użytkownika w tym poście”, który zostałby rozwiązany za pomocą dołączenia do RDBMS.getShortInfo
naturalnie spowodowałoby Przyszłość z powodu wywołania db. Aby zmniejszyć zagnieżdżanie wewnątrzfindAll
Użyłem Await (). Czy to dobry pomysł?
findAll
jest wywoływany z asynchronicznej akcji Play, konwertowany na Jsona i przesyłany przewodem.
def getIdeas(page: Int, perPage: Int) = Action.async {
for {
count <- IdeaDao.count
ideas <- IdeaDao.findAll(page, perPage)
} yield {
Ok(Json.toJson(ideas))
}
}
Więc myślę, że powrótSeq[Future[X]]
z findAll nie przyniesie lepszej wydajności, ponieważ i tak muszę czekać na wynik. Czy to jest poprawne?
Krótka skrzynka: Weź przyszłe wywołanie zwracające Sekwencję, użyj każdego elementu wyniku, aby utworzyć kolejne wywołanie Przyszłości, zwróć wynik do akcji asynchronicznej w taki sposób, aby nie wystąpiły sytuacje blokowania.