flatMap
e map
sono i tuoi amici! Questi due metodi del tipo Promise
consentono di trasformare il risultato di un Promise[A]
in un altro Promise[B]
.
Ecco un semplice esempio di loro in azione (Ho volutamente scritto in modo esplicito più annotazioni di tipo quanto necessario, solo per aiutare a capire dove avvengono trasformazioni):
def preferredSongsAndArtist = Action {
// Fetch the list of your preferred songs from Web Service “A”
val songsP: Promise[Response] = WS.url(WS_A).get
val resultP: Promise[List[Something]] = songsP.flatMap { respA =>
val songs: List[Song] = Json.fromJson(respA.json)
// Then, for each song, fetch the artist detail from Web Service “B”
val result: List[Promise[Something]] = songs.map { song =>
val artistP = WS.url(WS_B(song)).get
artistP.map { respB =>
val artist: Artist = Json.fromJson(respB.json)
// Then, generate and return something using the song and artist
val something: Something = generate(song, artist)
something
}
}
Promise.sequence(result) // Transform the List[Promise[Something]] into a Promise[List[Something]]
}
// Then return the result
Async {
resultP.map { things: List[Something] =>
Ok(Json.toJson(things))
}
}
}
Senza le annotazioni di tipo non necessarie e utilizzando la “ per la comprensione "notazione, è possibile scrivere il seguente codice più espressivo:
def preferredSongsAndArtist = Action {
Async {
for {
// Fetch the list of your preferred songs from Web Service “A”
respA <- WS.url(WS_A).get
songs = Json.fromJson[List[Song]](respA.json)
// Then, for each song, fetch the artist detail from Web Service “B”
result <- Promise.sequence(songs.map { song =>
for {
respB <- WS.url(WS_B(song)).get
artist = Json.fromJson[Artist](respB.json)
} yield {
// Then, generate and return something using the song and artist
generate(song, artist)
}
})
// Then return the result
} yield {
Ok(Json.toJson(result))
}
}
}
fonte
2012-04-03 13:11:06
Grazie per la risposta. Analizzo e collaudo questa soluzione al più presto. – YoT
@julien Cosa succede se uno dei servizi Web chiama timeout o restituisce un 500? getOrElse? –
La promessa sarà riscattata con un valore [Gettato] (http://www.playframework.org/documentation/api/2.0/scala/play/api/libs/concurrent/Thrown.html). Puoi gestire questo caso usando [extend] (http://www.playframework.org/documentation/api/2.0/scala/index.html#play.api.libs.concurrent.Promise) per esempio. –