4

我使用枚举器模式通过 WS.url 每秒检索一些推文

Enumerator.fromCallback[String](() => 
        Promise.timeout(WS.url("http://search.twitter.com/search.json?q="+query+"&rpp=1").get().map { response =>
            val tweets = response.json \\ "text"
            tweets match {
                case Nil => "Nothing found!"
                case head :: tail => query + " : " + head.as[String]
            }
        }.map(Some.apply).value.get, 1000 milliseconds)
  )

我的问题是

Enumerator.fromCallback[String]() 

正在等待一个

Promise[Option[String]]

由于 WS.url(...).get 返回一个 Promise,并且当我使用 Promise.timeout 每秒重新启动调用时,

我有一个

Promise[Promise[Option[String]]] 

所以我必须使用 value.get 来获得好的类型,所以对于异步方面来说它看起来不是很干净。

这段代码有效,但我的问题是:有没有更好、更优雅的方法来实现这一目标?我可以轻松地从另一个 Promise 和 Promise.timeout 中获得 Promise 吗?

谢谢 :)

4

1 回答 1

4

Promise是一个 monad,一般来说,当你发现自己有一个嵌套的 monad 时,你想把 a 粘flatMap在某个地方。在你的情况下,这样的事情应该有效:

import akka.util.duration._
import play.api.libs.concurrent._
import play.api.libs.iteratee._
import play.api.libs.ws._

val query = "test"
val url = WS.url("http://search.twitter.com/search.json?q=" + query + "&rpp=1")

val tweets = Enumerator.fromCallback[String](() => 
  Promise.timeout(url.get, 1000 milliseconds).flatMap(_.map { response =>
    (response.json \\ "text") match {
      case Nil => "Nothing found!"
      case head :: _ => query + " : " + head.as[String]
    }
  }.map(Some.apply))
)

我个人会这样写:

val tweets = Enumerator.fromCallback[String](() => 
  Promise.timeout(url.get, 1000 milliseconds).flatMap(_.map(
    _.json.\\("text").headOption.map(query + " " + _.as[String])
  ))
)

并且不要对"Nothing found!"消息大惊小怪,但取决于您到底在做什么,这可能不合适。

于 2012-08-05T16:04:04.237 回答