如果没有使用期货,为什么期货会被理解?

时间:2014-02-26 21:36:15

标签: scala playframework playframework-2.0 future scala-2.10

我正在尝试实现一个将请求缓存到外部API的系统。如果响应在缓存中,则不应向外部站点发出请求。

我有两种方法:

// Check to see if the response is in the database
def checkCache(searchParameters: JsValue): Future[Option[JsValue]]

// Call the external API and get the JSON response
def getResponse(path: String): Future[JsValue]

然后我尝试执行以下操作:

val json: Future[JsValue] = for {
  databaseJson <- checkCache(searchParameters)
  externalJson <- getResponse(path)
} yield databaseJson match {
  case None => externalJson
  case Some(x) => x
}

这样做有效,但是一直向外部API发出请求,即使返回了缓存结果也是如此。这显然不是我想要的,因为它很慢。

我该如何解决这个问题?

3 个答案:

答案 0 :(得分:4)

for comprehension映射了期货,而不是其中的Option。您的代码将转换为此

checkCache(searchParameters) flatMap { databaseJson =>
  getResponse(path) map { externalJson =>
    databaseJson match {
      case None => externalJson
      case Some(x) => x
    }
  }
}

所以你总是明显地打电话给getResponse()

你需要的东西(未经测试):

checkCache(searchParameters) flatMap { databaseJson =>
  databaseJson match {
    case None => getResponse(path)
    case Some(x) => Future.successful(x)
  }
}

答案 1 :(得分:2)

这有点俗气,但仍然:

checkCache(params) map (_.get) fallbackTo getResponse(path)

也未经过测试。

更新

我不喜欢None.get转换为失败,但实际上这根本不是俗气,而是很自然。更自然地:

checkCache(params) filter (_.nonEmpty) map (_.get) fallbackTo getResponse(path)

Some.get现在只是一个疣,因为两个期货的不对称性(它们不是Option)。

答案 2 :(得分:2)

你也可以试一试:

val json: Future[JsValue] = for {
  databaseJson <- checkCache(searchParameters)
  json <- databaseJson.fold(getResponse(path))(js =>Future.successful(js))
} yield json

与Marius Soutier的回答类似,但在理解中通过fold权限进行选项检查。