flatMap
和map
是你的朋友! Promise
類型的這兩種方法允許將Promise[A]
的結果轉換爲另一個Promise[B]
。
這裏是他們的行動中一個簡單的例子(我特意寫了明確更多類型的註釋比需要,只是爲了幫助理解其中的轉換髮生):
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))
}
}
}
沒有不必要的類型註釋,並使用「理解「符號,你可以寫下面更富有表現力的代碼:
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))
}
}
}
謝謝你的回答。我儘快分析和測試這個解決方案。 – YoT 2012-04-03 13:35:47
@ julien如果任何Web服務調用超時或返回500,會發生什麼情況? getOrElse? – 2012-04-25 08:06:52
該承諾將以[Thrown](http://www.playframework.org/documentation/api/2.0/scala/play/api/libs/concurrent/Thrown.html)值進行兌換。例如,您可以通過使用[extend](http://www.playframework.org/documentation/api/2.0/scala/index.html#play.api.libs.concurrent.Promise)來處理這種情況。 – 2012-04-25 13:28:50