簡體   English   中英

結合期貨相互依賴

[英]Combining Futures dependent on each other

我正在使用Scala向API發出HTTP GET請求(確切地說是Play Framework的WS),它響應JSON響應,看起來像;

{
  data: [
    {text: "Hello there", id: 1},
    {text: "Hello there again", id: 2}
  ],
  next_url: 'http://request-this-for-more.com/api?page=2' //optional
}

因此,返回的JSON中的next_url字段可能存在也可能不存在。

我的方法需要做的是從調用第一個URL開始,檢查響應是否有next_url ,然后對其進行GET。 最后,我應該將響應中的所有data字段合並到所有數據字段的單個未來中。 當響應中沒有next_url時,我終止。

現在,以阻塞方式執行此操作更容易,但我不想這樣做。 解決這樣的問題的最佳方法是什么?

可能有一種方法可以在scalaz中的某個地方執行此操作,但如果您不知道特定的解決方案,通常可以使用遞歸和flatMap構造一個。 就像是:

//Assume we have an async fetch method that returns Result and Option of next Url
def fetch(url: Url): Future[(Result, Option[Url])] = ...

//Then we can define fetchAll with recursion:
def fetchAll(url: Url): Future[Vector[Result]] =
  fetch(url) flatMap {
    case (result, None) => Future.successful(Vector(result))
    case (result, Some(nextUrl)) =>
      fetchAll(nextUrl) map {results => result +: results}
  }

(注意,這為每個調用使用一個堆棧幀 - 如果你想要進行數千個提取,那么我們需要更仔細地編寫它,以便它是尾遞歸的)

對於像這樣的案例, Future.flatMap方法很普遍

假設你有這樣的東西:

case class Data(...)
def getContent(url:String):Future[String]
def parseJson(source:String):Try[JsValue]
def getData(value: JsValue):Seq[Data]

JsValue類型的方法靈感來自play json庫

def \ (fieldName: String): JsValue
def as[T](implicit ...):T //probably throwing exception

你可以組成最終結果

def innerContent(url:String):Future[Seq[Data]] = for {
  first <- getContent(url)
  json <- Future.fromTry(parseJson(first))
  nextUrlAttempt = Try((json \ "next_url").as[String])
  dataAttempt = Try(getData(json \ "data"))
  data <- Future.fromTry(dataAttempt)
  result <- nextUrlAttempt match {
    case Success(nextUrl) => innerContent(nextUrl)
    case Failure(_) => Future.successful(Seq())
} yield data ++ result

還要檢查針對復雜異步流的庫,例如:

  1. 玩迭代
  2. scalaz iteratees
  3. 斯卡拉茲流

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM