39 votes

Manière propre dans GWT / Java d'attendre la fin de plusieurs événements asynchrones

Quel est le meilleur moyen d'attendre que plusieurs fonctions de rappel asynchrones se terminent en Java avant de continuer. Plus précisément, j'utilise GWT avec AsyncCallback, mais je pense qu'il s'agit d'un problème générique. Voici ce que j'ai maintenant, mais il y a sûrement moyen plus propre ...

     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
    }
}
 

41voto

throp Points 396

J'ai écrit deux classes qui permettent de résoudre ce problème sur mon projet. Fondamentalement, chaque individu de rappel s'enregistre auprès d'un parent. Le parent attend chaque enfant de rappel pour terminer, puis déclenche son propre handleSuccess().

Le client code ressemble à ceci:

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);
}

J'ai écrit un post en expliquant ici: Parallèle des Appels Asynchrones dans GWT. La mise en œuvre de ces deux classes est liée à partir de ce post (désolé, ne peut pas donner les liens ici parce que je suis un newbie de l'utilisateur - pas assez de karma pour inclure plus de un lien!).

5voto

Jason Hall Points 15935

Comme @Epsen le dit, Future est probablement ce que vous voulez. Malheureusement, je ne crois pas que Future s sont compatibles avec GWT. Le projet gwt-async-future prétend apporter cette fonctionnalité à GWT, bien que je ne l'aie jamais essayée. Ça vaut peut-être le coup d'oeil.

4voto

Sasquatch Points 111

J'ai lutté avec moi-même, et j'ai utilisé plusieurs méthodes de la "chaîne" de l'un est juste moche (mais peut être amélioré si vous créez des classes au lieu de inline classes pour chaque méthode).

Une variante de votre propre version qui fonctionne bien pour moi:

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
}

Je me suis contenté de créer un compteur pour le nombre d'appels que je vais faire, puis chaque async résultat des appels d' ready() (assurez-vous de le faire sur l'échec des méthodes de trop, sauf si vous allez faire quelque chose de différent)

Dans la méthode, je décrémente le compteur et voir si il y a encore des appels en attente.

C'est toujours aussi moche, mais il vous permet d'ajouter des appels en tant que de besoin.

2voto

Sripathi Krishnan Points 15402

D'abord et avant tout - ne jamais entrer dans une telle situation. Refonte de votre RPC services tels que tous les utilisateurs de flux/écran nécessite tout au plus un seul appel RPC de travail. Dans ce cas, vous faites trois appels vers le serveur, et c'est juste un gaspillage de bande passante. Le temps de latence sera juste tuer votre application.

Si vous ne pouvez pas vraiment et ont besoin d'un hack, utilisez une Minuterie pour interroger périodiquement si toutes les données ont été téléchargées. Le code que vous avez collé ci-dessus suppose login() la méthode sera la dernière à la fin - ce qui est faux. Sa peut être le premier à terminer, puis votre application sera dans un état indéterminé - ce qui est très difficile à déboguer.

1voto

Davy Meers Points 1108

Juste jeter quelques idées:

Les rappels de feu, de GwtEvent à l'aide de la HandlerManager. La classe contenant le prêt méthodes est enregistré auprès de la HandlerManager comme un Gestionnaire d'événements pour les événements déclenchés par les méthodes de rappel, et tient l'état (bookAPIAvailable, searchAPIAvailable, appLoaded).

Lorsqu'un événement arrive l'état est changé, et nous vérifions si tous les états sont comme souhaité.

Pour un exemple d'utilisation de la GWTEvent, HandlerManager et de Gestionnaire d'événements, voir http://www.webspin.be/?p=5

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X