Expand GWT Asynchronous Callbacks

I have the following problem: I am trying to simulate a process using GWT, where I have a couple of views with several submit buttons. And pressing button1 will create an interaction with the server, and if everything is in order, the next view will be loaded. My problem now is that I get really nasty spaghetti code (just a very high level to show you what I mean):

onClick { AsyncCallback { onSuccess { load new view with another clickhandler and an asynccallback } } } 

Is there any way to create some kind of abstraction or something else? Maybe a state template? How? Many thanks!

+6
source share
5 answers

This is actually a very good question - and perhaps one without a definitive answer. This is a problem that applies to many frameworks, not just GWT, so I like your idea of ​​looking at this with some simplified code. I will do it a little longer to show how even very simple callbacks look like:

Nested Callbacks

 alice.call("a", new Callback() { @Override public void onSuccess() { bob.call("b", new Callback() { @Override public void onSuccess() { charlie.call("c", new Callback() { @Override public void onSuccess() { daisy.call("d", new Callback() { @Override public void onSuccess() { // finished } }); } }); } }); } }); 

Named Callbacks

You can use your IDE to reorganize this easily into named callbacks (hint: read the callbacks from the bottom up!):

 final Callback daisyCallback = new Callback() { @Override public void onSuccess() { // finished } }; final Callback charlieCallback = new Callback() { @Override public void onSuccess() { daisy.call("d", daisyCallback); } }; final Callback bobCallback = new Callback() { @Override public void onSuccess() { charlie.call("c", charlieCallback); } }; final Callback aliceCallback = new Callback() { @Override public void onSuccess() { bob.call("b", bobCallback); } }; alice.call("a", aliceCallback); 
  • Problem: The control flow is not immediately apparent.
  • However, the IDE can help by using Link Finder (Ctrl-G in Eclipse) or something similar.

Event Bus (or Observer / Publish-Subscribe Template)

Here's what the same calls look like with the event bus:

 alice.call("a", new Callback() { @Override public void onSuccess() { bus.fireEvent(BusEvent.ALICE_SUCCESSFUL_EVENT); } }); bus.addEventListener(BusEvent.ALICE_SUCCESSFUL_EVENT, new BusEventListener() { @Override public void onEvent(final BusEvent busEvent) { bob.call("b", new Callback() { @Override public void onSuccess() { bus.fireEvent(BusEvent.BOB_SUCCESSFUL_EVENT); } }); } }); bus.addEventListener(BusEvent.BOB_SUCCESSFUL_EVENT, new BusEventListener() { @Override public void onEvent(final BusEvent busEvent) { charlie.call("c", new Callback() { @Override public void onSuccess() { bus.fireEvent(BusEvent.CHARLIE_SUCCESSFUL_EVENT); } }); } }); bus.addEventListener(BusEvent.CHARLIE_SUCCESSFUL_EVENT, new BusEventListener() { @Override public void onEvent(final BusEvent busEvent) { daisy.call("d", new Callback() { @Override public void onSuccess() { bus.fireEvent(BusEvent.DAISY_SUCCESSFUL_EVENT); } }); } }); bus.addEventListener(BusEvent.DAISY_SUCCESSFUL_EVENT, new BusEventListener() { @Override public void onEvent(final BusEvent busEvent) { // finished } }); 
  • Under the right circumstances (when it is very clear what each event means, and if you have too many of them), this template can make things very beautiful and understandable.
  • But in other cases, it can make the control flow more confusing (and you can easily get twice the lines of code).
  • It’s harder to use your IDE to learn about the control flow.
  • The GWT history engine is a very positive example of where it is wise to use this method.

Divide and conquer

In my experience, it is often a good idea to “divide and win” by mixing nested and named callbacks:

 final Callback charlieCallback = new Callback() { @Override public void onSuccess() { daisy.call("d", new Callback() { @Override public void onSuccess() { // finished } }); } }; alice.call("a", new Callback() { @Override public void onSuccess() { bob.call("b", new Callback() { @Override public void onSuccess() { charlie.call("c", charlieCallback); } }); } }); 

Depending on the situation, two nested callbacks often remain readable, and they reduce the transitions between methods when reading code by 50%.

(I created a pastebin of my examples here if you like playing with them: http://pastebin.com/yNc9Cqtb ) sub>

+6
source

Spaghetti code is a complex issue in GWT, as in Javascript, where most of your code is structured around asynchronous callbacks.

Some of the methods for solving this problem described in the answers to this question can be applied.

+1
source

The proposed approach, in order to avoid communication between widgets, is to use EventBus. Read more here https://developers.google.com/web-toolkit/articles/mvp-architecture#events

Hope this helps.

0
source

Use MVP from the start. Use actions and places. Your code will be clean.

0
source
 changeview(boolean first){ if(first) { firstView.setVisible(true); secondView.setVisible(false); }else{ firstView.setVisible(false); secondView.setVisible(true); } } onClick { AsyncCallback { onSuccess { changeView(false); } } } 

Switch between the views above.

0
source

Source: https://habr.com/ru/post/920198/


All Articles