At issue is that the demos that come with GWT tend to lean heavily on
anonymous inner classes, which sometimes lead to misunderstandings
about what is really going on in the code. So without further ado, the
pitfall:
protected String someString;
public void callService(){
SomeServiceAsync service = (SomeServiceAsync)
GWT.create(SomeService.class);
((ServiceDefTarget)
service).setServiceEntryPoint(GWT.getModuleBaseURL()+"SomeService";
service.doSomething( new AsyncCallback<String>(){
public void onFailure(Throwable caught) {
Window.alert("DOH!");
}
public void onSuccess(String result) {
someString = result;
}
});
Window.alert(someString);
}
And inevitably we'll hear "My RPC doesn't work" or "It doesn't work
the first time, but after that it is fine"
The problem here is that the unwitting user, new to Asynchronous
programming has tried to make the asynchronous request synchronous.
How's that? Well let me translate that little bit of java code into a
plain english situation that you could encounter any old day.
Imagine if you will ...
You are sitting on the couch watching TV, and knowing that you are out
of beer, you ask your spouse to please run down to the liquor store
and fetch you some. As soon as you see your spouse walk out the front
door, you get up off the couch and trundle into the kitchen and open
the fridge. To your surprise, there is no beer!
Well of course there is no beer, your spouse is still on the trip to
the liquor store. You've gotta wait until [s]he returns before you can
expect to have a beer.
So, lets rewrite our little RPC with that little tidbit in mind.
protected Fridge kitchenFridge;
public void getMeSomeBeer(){
SpouseServiceAsync spouse = (SpouseServiceAsync)
GWT.create(SpouseService.class);
((ServiceDefTarget)
service).setServiceEntryPoint(GWT.getModuleBaseURL()+"SpouseService";
spouse.goToLiquorStorePlease(Beer.SIX_PACK, new
AsyncCallback<Beer>(){
public void onFailure(Throwable caught) {
Window.alert("DOH!");
}
public void onSuccess(Beer your6pack) {
kitchenFridge.put(your6pack);
goDrinkYourBeer();
}
});
}
public Burp goDrinkYourBeer(){
Beer beer = kitchenFridge.get(Beer.BOTTLE);
beer.open();
/* its your beer, you figure it out */
return new Burp(Burp.LOUD);
}
So there you have it, A subtle but very important difference.
Now, once that little revelation hits home, the very next thing that
folks new to GWT ask is, "But I really need it to be Synchronous"
No, you don't!, and in fact you really don't want it to be ...
Same scenario, only synchronous
... spouse walks out the door ...
now, the entire world around you stops, you don't get to breath,
answer the door, or finish watching your show while [s]he runs across
town to fetch your beer. You just get to sit there not moving a
muscle, and turning blue until you lose consciousness ... waking up
some indefinite time later surrounded by EMTs and a spouse saying oh,
hey, I got your beer.
Synchronous requests in the web browser lock up the entire browser,
you can't switch tabs, can't browse other pages, and in some cases
can't even close the browser until that request returns. That is the
definition of naughty behavior on the part of the programmer. That is
the reason that GWT doesn't provide a way to perform synchronous
requests.
Hopefully this little plain english scenario will help some
programmers new to GWT navigate the sometimes confusing concept that
is the Asynchronous request.
-jason
That was awesome. I nominate it for inclusion in some kind of fixed
documentation.
Ian