将多个承诺组合成一个承诺 PlayFramework 2.4
Compose multiple promises into one promise PlayFramework 2.4
我正在尝试学习 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 中。那我convert/map它就长了。我无法做的是如何将这三个承诺合二为一,一旦所有三个承诺都被兑现 convert/map 就变成了 json 和 return 结果。在较早版本的 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() 方法,它 return 是 Promise 被赎回后的值。那我该用什么?
waitAll
已替换为 F.Promise.sequence
。
来自docs
public static <A> F.Promise<java.util.List<A>> sequence(java.lang.Iterable<F.Promise<A>> promises)
Combine the given promises into a single promise for the list of results. The sequencing operations are performed in the default ExecutionContext.
Parameters:
promises - The promises to combine
Returns:
A single promise whose methods act on the list of redeemed promises
更新
关于后半题,不需要调用.get()
,因为promises已经完成了
事实上,您可以去掉单独的 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 需要 Java8,这是玩转 lambda 的好机会!
我正在尝试学习 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 中。那我convert/map它就长了。我无法做的是如何将这三个承诺合二为一,一旦所有三个承诺都被兑现 convert/map 就变成了 json 和 return 结果。在较早版本的 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() 方法,它 return 是 Promise 被赎回后的值。那我该用什么?
waitAll
已替换为 F.Promise.sequence
。
来自docs
public static <A> F.Promise<java.util.List<A>> sequence(java.lang.Iterable<F.Promise<A>> promises)
Combine the given promises into a single promise for the list of results. The sequencing operations are performed in the default ExecutionContext.
Parameters: promises - The promises to combine
Returns: A single promise whose methods act on the list of redeemed promises
更新
关于后半题,不需要调用.get()
,因为promises已经完成了
事实上,您可以去掉单独的 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 需要 Java8,这是玩转 lambda 的好机会!