我有以下代码与几个异步调用相互依赖(例如,调用可以是apis REST),并在最后处理所有结果。这是我的示例代码:
private void foo1(String uuid, Handler<AsyncResult<JsonObject>> aHandler) {
//call json api, for example
JsonObject foo1 = new JsonObject();
foo1.put("uuid", "foo1");
aHandler.handle(Future.succeededFuture(foo1));
}
private void foo2(String uuid, Handler<AsyncResult<JsonObject>> aHandler) {
//call json api, for example
JsonObject foo2 = new JsonObject();
foo2.put("uuid", "foo2");
aHandler.handle(Future.succeededFuture(foo2));
}
private void foo3(String uuid, Handler<AsyncResult<JsonObject>> aHandler) {
//call json api, for example
JsonObject foo3 = new JsonObject();
foo3.put("uuid", "foo3");
aHandler.handle(Future.succeededFuture(foo3));
}
private void doSomething(JsonObject result1, JsonObject result2, JsonObject result3, Handler<AsyncResult<JsonObject>> aHandler) {
JsonObject finalResult =new JsonObject();
aHandler.handle(Future.succeededFuture(finalResult));
}
private void processToRefactor (String uuid, Handler<AsyncResult<JsonObject>> aHandler) {
foo1(uuid, ar -> {
if (ar.succeeded()) {
JsonObject foo1 = ar.result();
foo2(foo1.getString("uuid"), ar2 ->{
if (ar2.succeeded()) {
JsonObject foo2 = ar2.result();
foo3(foo2.getString("uuid"), ar3 -> {
if (ar3.succeeded()) {
JsonObject foo3 = ar3.result();
doSomething(foo1, foo2, foo3, aHandler);
} else {
ar3.cause().printStackTrace();
}
});
} else {
ar2.cause().printStackTrace();
}
});
} else {
ar.cause().printStackTrace();
}
});
}
在前面的代码中,我可以在&#34; doSomething&#34;中使用所有结果。所有呼叫都成功的方法。 我试图使用简单的&#34; HelloWord&#34;重构这个代码。示例来自以下链接https://streamdata.io/blog/vert-x-and-the-async-calls-chain/
这是我的结果:
private void process(String uuid, Handler<AsyncResult<JsonObject>> aHandler) {
Future<JsonObject> future = Future.future();
future.setHandler(aHandler);
Future<JsonObject> futureFoo1 = Future.future();
foo1(uuid, futureFoo1);
futureFoo1.compose(resultFoo1 -> {
Future<JsonObject> futureFoo2 = Future.future();
foo2(resultFoo1.getString("uuid"), futureFoo2);
return futureFoo2;
}).compose(resultFoo2 ->{
Future<JsonObject> futureFoo3 = Future.future();
foo3(resultFoo2.getString("uuid"), futureFoo3);
return futureFoo3;
}).compose(resultFoo3 -> {
// How to get result1, result2 and result3?
// doSomething(resultFoo1, resultFoo2, resultFoo3, aHandler);
}, future);
}
新代码更清晰,更清晰,但在使用撰写时,在调用函数的时候&#34; doSomething&#34;我没有可用的所有调用结果。 如何在链的末尾获得所有结果?
另一方面,如果其中一个apis调用方法返回一个数组怎么办?也就是说,对于数组的每个元素,应用一系列函数,独立事实上有些人有结果,有些则没有。例如:
private void foo1Array(String uuid, Handler<AsyncResult<JsonArray>> aHandler) {
//call json api that return array, for example
JsonArray result = new JsonArray();
JsonObject foo1 = new JsonObject();
foo1.put("uuid", "foo1");
JsonObject foo2 = new JsonObject();
foo1.put("uuid", "foo2");
JsonObject foo3 = new JsonObject();
foo1.put("uuid", "foo3");
result.add(foo1);
result.add(foo2);
result.add(foo3);
aHandler.handle(Future.succeededFuture(result));
}
private void processArray(String uuid, Handler<AsyncResult<JsonObject>> aHandler) {
Future<JsonObject> future = Future.future();
future.setHandler(aHandler);
Future<JsonArray> futureFoo1 = Future.future();
foo1Array(uuid, futureFoo1);
futureFoo1.compose(resultArray -> {
List<Future> futures = new ArrayList<Future>();
for (int i = 0; i < resultArray.size(); i ++) {
JsonObject resultFoo1 = resultArray.getJsonObject(i);
Future<JsonObject> futureFoo2 = Future.future();
foo2(resultFoo1.getString("uuid"), aHandler);
futures.add(futureFoo2);
}
CompositeFuture.any(futures).setHandler(ar -> {
//What to do here?
});
}, future);
}
如何使用foo1Array的结果调用函数foo2,foo3,...然后在doSomething中使用它?
答案 0 :(得分:1)
你的初步方法实际上并不太糟糕。
为了改善代码以实现更好的&#34;可组合性&#34;,您应该将每个fooX方法的处理程序输入arg更改为扩展Handler<AsyncResult<JsonObject>>
(例如Future)的内容,并返回相同的处理程序作为结果,因此它在`Future.compose中变得更好用,因为传入的处理程序可以用作每个组合的返回值:
private <T extends Handler<AsyncResult<JsonObject>>> T foo1(String uuid, T aHandler) {
JsonObject foo1 = new JsonObject().put("uuid", "foo1");
aHandler.handle(Future.succeededFuture(foo1));
return aHandler; //<-- return the handler here
}
其次,为了在最后阶段访问所有三个结果,您必须在链外宣布三个期货。现在,你可以使用每个foo方法的输出很好地链接期货,作为每个组合的结果。
Future<JsonObject> futureFoo1 = Future.future();
Future<JsonObject> futureFoo2 = Future.future();
Future<JsonObject> futureFoo3 = Future.future();
foo1(uuid, futureFoo1).compose(resultFoo1 -> foo2(resultFoo1.getString("uuid"), futureFoo2))
.compose(resultFoo2 -> foo3(resultFoo2.getString("uuid"), futureFoo3))
.compose(resultFoo3 -> doSomething(futureFoo1.result(), //access results from 1st call
futureFoo2.result(), //access results from 2nd call
resultFoo3,
Future.<JsonObject>future().setHandler(aHandler))); //pass the final result to the original handler
如果你不能忍受&#34;杂质&#34;这种方法(定义外链的期货并在函数内修改它们),你必须传递每个方法的原始输入值(=前一次调用的输出)以及结果,但我怀疑这会使代码更多可读的。
为了在一个compose方法中改变类型,你必须使用fooX方法 转换,不返回原始处理程序,而是返回具有不同类型的新Future
private Future<JsonArray> foo2(String uuid, Handler<AsyncResult<JsonObject>> aHandler) {
JsonObject foo2 = new JsonObject();
foo2.put("uuid", "foo2" + uuid);
aHandler.handle(Future.succeededFuture(foo2));
JsonArray arr = new JsonArray().add("123").add("456").add("789");
return Future.succeededFuture(arr);
}
答案 1 :(得分:0)
如果您想要更简单且没有回调地狱代码然后切换到rx
,您的上述代码将变成这样的内容:
private Single<JsonObject> foo1(String uuid) {
JsonObject foo1 = new JsonObject();
foo1.put("uuid", "foo1");
return Single.just(foo1);
}
private Single<JsonObject> foo2(String uuid) {
JsonObject foo2 = new JsonObject();
foo2.put("uuid", "foo2");
return Single.just(foo2);
}
private Single<JsonObject> foo3(String uuid) {
JsonObject foo3 = new JsonObject();
foo3.put("uuid", "foo3");
return Single.just(foo3);
}
private Single<JsonObject> doSomething(String uuid) {
JsonObject finalResult =new JsonObject();
return Single.zip(foo1(uuid), foo2(uuid), foo3(uuid))
.map(results -> {
// Map zip results to finalResult
return finalResult;
});
}
private void processToRefactor (String uuid, Handler<AsyncResult<JsonObject>> aHandler) {
doSomething(uuid).subscribe();
}