尽快为客户提供多种结果期货

时间:2014-04-22 22:45:35

标签: scala asynchronous playframework playframework-2.2 future

我有一个页面由我使用不同的远程服务器调用获得的数据填充。有些请求比其他请求花费的时间更长,我现在做事的方式是我立即执行所有调用并将整个事件包装在Future中,然后将整个事件放在Action.async中用于播放处理。

理论上,这可以完成这项工作,但我不希望我的用户等待很长时间,而是开始逐个加载页面。这意味着只要数据可用于远程服务器的给定请求,就应该将其作为Json或其他任何内容发送给客户端。

我可以使用EventSource部分实现这一点,方法是通过这样的方式修改Play的事件源示例:

Ok.chunked((enumerator1  &> EventSource()) >- (enumerator2  &> EventSource())).as("text/event-stream")

和枚举者如下:

val enumerator1: Enumerator[String] = Enumerator.generateM{
   Future[Option[String]]{Thread.sleep(1500); Some("Hello")}
}

val enumerator2: Enumerator[String] = Enumerator.generateM{
   Future[Option[String]]{Thread.sleep(2000); Some("World!")}
}

正如你可能已经猜到的那样,我期待着"你好" 1.5秒后然后"世界!" 0.5秒后发送给客户,但我最终收到了#34; Hello"每1.5秒和#34;世界!"每2秒。

我的问题是:

  1. 使用上述方法将信息正确传送到客户后,是否有办法停止发送信息?

  2. 有没有更好的方法来实现我的目标?

1 个答案:

答案 0 :(得分:0)

您不希望generateM,它可以构建可以返回多个值的枚举器。 generateM使用一个函数返回Some,生成EnumeratorNone的下一个值,以表示Enumerator已完成。因为您的函数始终返回Some,所以您创建了长度无限的Enumerator

您只想将Future转换为Enumerator,以使用单个元素创建Enumerator

Enumerator.flatten(future.map(Enumerator(_)))

此外,您可以交错您的枚举器,然后将结果提供给EventSource()。括号也是不必要的(以>开头的方法优先于&的方法。

enumerator1  >- enumerator2 &> EventSource()