我正在尝试学习Play Framework 2.4。我正在尝试使用Promise以异步方式访问不同的网页。以下是代码:
final long start = System.currentTimeMillis();
F.Function<WSResponse,Long> timing = new F.Function<WSResponse, Long>() {
@Override
public Long apply(WSResponse wsResponse) throws Throwable {
return System.currentTimeMillis()-start;
}
};
F.Promise<Long> google = ws.url("http://www.google.com").get().map(timing);
F.Promise<Long> yahoo = ws.url("http://www.yahoo.com").get().map(timing);
F.Promise<Long> bing = ws.url("http://www.bing.com").get().map(timing);
正如您所看到的,我正在使用get函数来获取所请求的页面并将结果放入Future Promise中。然后我转换/映射到long。我无法做的是如何将这三个承诺组合成一个,一旦所有三个承诺被兑换成转换/映射到json并返回结果。在早期版本的Play中,它可以由F.Promise.waitAll(google,yahoo,bing).map(...)
完成,但我无法在Play 2.4中完成。请建议
EDIT1 :根据以下答案,我使用了如下序列:
return F.Promise.sequence(google, yahoo, bing).map(new F.Function<List<Long>, Result>() {
@Override
public Result apply(List<Long> longs) throws Throwable {
Map<String, Long> data = new HashMap<String, Long>();
data.put("google", google.get());
data.put("yahoo", yahoo.get());
data.put("bing", bing.get());
return ok(Json.toJson(data));
}
});
但是,我收到错误,无法解析google.get()方法并且无法应用Json。我在这里缺少什么?
编辑2。使用return ok((JsonNode) Json.toJson((Writes<Object>) data));
修复了Json错误但是,我仍然无法解决之前的错误,即google.get()方法无法在行中解析data.put("google", google.get());
编辑3。似乎Play2.4没有get()方法,一旦兑换了Promise,它就会返回值。那我该怎么用?
答案 0 :(得分:6)
waitAll
已替换为F.Promise.sequence
。
来自docs
public static <A> F.Promise<java.util.List<A>> sequence(java.lang.Iterable<F.Promise<A>> promises)
将给定的承诺合并到结果列表的单个承诺中。排序操作在默认的ExecutionContext中执行。
参数: 承诺 - 结合的承诺
返回: 单一承诺,其方法作用于兑换承诺清单
<强>更新强>
关于问题的后半部分,您无需致电.get()
,因为承诺已经完成。
事实上,你可以摆脱各个promise变量,然后直接将它们传递给序列。结果列表将包含相同顺序的结果(Google首先,然后是Yahoo,然后是Bing,在这种情况下)。
整个事情应该是这样的:
package controllers;
import java.util.HashMap;
import java.util.Map;
import play.libs.F;
import play.libs.Json;
import play.libs.ws.WS;
import play.libs.ws.WSResponse;
import play.mvc.Controller;
import play.mvc.Result;
import play.mvc.Results;
public class Application extends Controller {
public F.Promise<Result> index() {
final long start = System.currentTimeMillis();
final F.Function<WSResponse,Long> timing = response -> System.currentTimeMillis() - start;
return F.Promise.sequence(WS.url("http://www.google.com").get().map(timing),
WS.url("http://www.yahoo.com").get().map(timing),
WS.url("http://www.bing.com").get().map(timing))
.map(list -> {
Map<String, Long> data = new HashMap<>();
data.put("google", list.get(0));
data.put("yahoo", list.get(1));
data.put("bing", list.get(2));
return data;
})
.map(Json::toJson)
.map(Results::ok);
}
}
最后,由于Play 2.4需要Java 8,这是一个玩lambdas的好机会!