GWT/Java中等待多个异步事件完成的干净方法

GWT/Java中等待多个异步事件完成的干净方法,java,gwt,google-ajax-api,Java,Gwt,Google Ajax Api,在继续之前,在Java中等待多个异步回调函数完成的最佳方式是什么。具体来说,我将GWT与AsyncCallback一起使用,但我认为这是一个一般性问题。这是我现在拥有的,但肯定有更干净的方法 AjaxLoader.loadApi("books", "0", new Runnable(){ public void run() { bookAPIAvailable = true; ready(); }}, nul

在继续之前,在Java中等待多个异步回调函数完成的最佳方式是什么。具体来说,我将GWT与AsyncCallback一起使用,但我认为这是一个一般性问题。这是我现在拥有的,但肯定有更干净的方法

    AjaxLoader.loadApi("books", "0", new Runnable(){
        public void run() {
            bookAPIAvailable = true;
            ready();
        }}, null);
    AjaxLoader.loadApi("search", "1", new Runnable(){
        public void run() {
            searchAPIAvailable = true;
            ready();
        }}, null);


    loginService.login(GWT.getHostPageBaseURL(), new AsyncCallback<LoginInfo>() {
        public void onSuccess(LoginInfo result) {
            appLoaded  = true;
            ready();
        }
    });

private void ready() {
    if(bookAPIAvailable && searchAPIAvailable && appLoaded) {
                // Everything loaded
    }
}
AjaxLoader.loadApi(“books”,“0”,new Runnable()){
公开募捐{
bookAPIAvailable=true;
ready();
}},空);
loadApi(“搜索”,“1”,新的可运行(){
公开募捐{
searchAPIAvailable=true;
ready();
}},空);
loginService.login(GWT.getHostPageBaseURL(),new AsyncCallback()){
成功时公共无效(登录信息结果){
Apploated=true;
ready();
}
});
私有void ready(){
如果(bookAPIAvailable&&searchAPIAvailable&&Appload){
//装载的东西
}
}

首先,不要陷入这种情况。重新设计RPC服务,使每个用户流/屏幕最多只需要一个RPC调用即可工作。在这种情况下,您要对服务器进行三次调用,这只是在浪费带宽。延迟只会杀死你的应用程序


如果您不能并且确实需要黑客,请使用定期轮询是否所有数据都已下载。上面粘贴的代码假定login()方法将是最后一个完成的-这是错误的。它可能是第一个完成的,然后你的应用程序将处于一种不确定的状态,这很难调试。

就像@Epsen所说的,
未来可能就是你想要的。不幸的是,我不相信
Future
s与GWT兼容。该项目声称将此功能引入GWT,尽管我从未尝试过。这可能值得一看。

正如sri所说,最好的方案是重新设计应用程序,一次只调用后端一次。这避免了这种情况,并保留了带宽和延迟时间。在web应用程序中,这是您最宝贵的资源

尽管如此,GWT RPC模型并不能真正帮助您以这种方式组织事情。我自己也遇到过这个问题。我的解决方案是实现一个计时器。计时器将每X秒轮询一次结果,当检索到所有预期结果时,执行流可以继续


}

调用RPC,然后实例化一个新的PollTimer对象。这应该能奏效


GWT仿真不支持java.util.concurrent中的内容。在这种情况下我帮不了你。出于所有目的,您在客户端执行的所有代码都是单线程的。试着进入那种思维定势。

只是想一些想法:

回调使用HandlerManager触发一些GwtEvent。 包含ready方法的类在HandlerManager中注册为回调方法触发的事件的EventHandler,并保持状态(bookAPIAvailable、searchAPIAvailable、appLoaded)

当一个事件到达时,特定的状态被改变,我们检查是否所有的状态都符合要求


有关使用GWTEvent、HandlerManager和EventHandler的示例,请参见

,理想情况下,您希望按照其他海报中的说明进行操作,并在单个异步调用中尽可能多地执行操作。有时你不得不打一大堆单独的电话。以下是方法:

您希望链接异步调用。当最后一次异步完成(登录)时,将加载所有项目

public void someGwtClientSideMethod() {
    SomeServiceAsync someService = GWT.create(SomeService.class);
    ParallelCallback fooCallback = new ParallelCallback();
    ParallelCallback barCallback = new ParallelCallback();
    ParentCallback parent = new ParentCallback(fooCallback, barCallback) {
        public void handleSuccess() {
            doSomething(getCallbackData(1), getCallbackData(2));
        }
    };
    someService.foo(fooCallback);
    someService.bar(barCallback);
}
final AsyncCallback loginCallback=new AsyncCallback(){
成功时公共无效(登录信息结果){
//装载的东西
doSomethingNow();
}
};
final Runnable searchRunnable=new Runnable(){
公开募捐{
loginService.login(GWT.getHostPageBaseURL(),loginCallback);
}
};
final Runnable books Runnable=新Runnable(){
公开募捐{
loadApi(“搜索”,“1”,可搜索,空);
}
};
//启动一连串事件
loadApi(“books”,“0”,booksRunnable,null);
干杯


--Russ

我在我的项目中编写了两个类来解决这个问题。基本上,每个回调都注册到父回调。父级等待每个子级回调完成,然后触发它自己的handleSuccess()

客户端代码如下所示:


我在这里写了一篇文章解释它:。这两个类的实现是从那篇文章链接而来的(很抱歉,这里不能提供链接,因为我是一个新手用户-没有足够的业力来包含多个链接!)。

我自己也在努力解决这个问题,我使用了几种方法-链式链接会变得很难看(但如果您为每个方法创建类而不是内联类,则可以进行改进)

您自己的版本的变体对我很适用:

counter.count();
int-outstandingCalls=0;
{
杰出的呼叫++;
loadApi(“books”,“0”,new Runnable()){
公开募捐{
ready();
}},空);
杰出的呼叫++;
loadApi(“搜索”,“1”,新的可运行(){
公开募捐{
ready();
}},空);
杰出的呼叫++;
loginService.login(GWT.getHostPageBaseURL(),new AsyncCallback()){
成功时公共无效(登录信息结果){
ready();
}
//确保减小或以其他方式处理onFailure
});
}
私有void ready(){
如果(--outstandingCalls>0)返回;
//装载的东西
}
我所做的只是为我将要执行的调用数创建一个计数器,然后每个异步结果调用
ready()
(请确保在失败方法上也执行此操作,除非您要执行其他操作)

在ready方法中,我递减计数器,看看是否还有未完成的调用


它仍然很难看,但是它可以让你根据需要添加呼叫。

我做了一些类似于@Sasquatch的事情,但是使用了

public void someGwtClientSideMethod() {
    SomeServiceAsync someService = GWT.create(SomeService.class);
    ParallelCallback fooCallback = new ParallelCallback();
    ParallelCallback barCallback = new ParallelCallback();
    ParentCallback parent = new ParentCallback(fooCallback, barCallback) {
        public void handleSuccess() {
            doSomething(getCallbackData(1), getCallbackData(2));
        }
    };
    someService.foo(fooCallback);
    someService.bar(barCallback);
}
int outstandingCalls = 0;
{
outstandingCalls++;
 AjaxLoader.loadApi("books", "0", new Runnable(){
    public void run() {
        ready();
    }}, null);

outstandingCalls++;
AjaxLoader.loadApi("search", "1", new Runnable(){
    public void run() {
        ready();
    }}, null);


outstandingCalls++;
loginService.login(GWT.getHostPageBaseURL(), new AsyncCallback<LoginInfo>() {
    public void onSuccess(LoginInfo result) {
        ready();
    }
    // Be sure to decrement or otherwise handle the onFailure
});
}

private void ready() {
if (--outstandingCalls > 0) return;

// Everything loaded
}
public class CallbackCounter {
    private int outstanding;
    private final Callback<String, String> callback;
    private final String message;

    public CallbackCounter(int outstanding, Callback<String, String> callback, String callbackMessage) {
        this.outstanding = outstanding;
        this.callback = callback;
        this.message = callbackMessage;
    }

    public void count() {
        if (--outstanding <= 0) {
            callback.onSuccess(message);
        }
    }
}
counter.count();