Welcome to NavWin!
  

Introduction

One of the unusual (and powerful) features of the GWT environment is the ability to load segments of code on demand only. While the implementation is obviously very sophisticated for the most part, there is one area (namely the leftover segment) that has fairly severe restrictions. So long as you can understand this, then there are definite possibilities for loading large chunks of your application asynchronously, and the end user experience will be that much better.

How effective are split points

Split points can have a dramatic effect on your initial application download load times. Here is the current split report from my application. This includes all major control implementations, up to and including the date box and the editable grid control. As mentioned elsewhere, you get the compile report by specifying the –compileReport argument.

Below is the number of bytes that is saved by loading the DateBox asynchronously.

Split points

The first thing to understand is that the entire project is divided into segments called ‘split points’ and they have one of three types.

Split Point Type

Description

Initial load

Usually one split point that is loaded when the application loads. You goal should be to try and make this as small as possible in size. However you should not attempt to make it zero as some things must be loaded at the start so there is no benefit in trying to load them later on e.g. if your application always has a button on the start screen, then there is no point trying to load the button controls asynchronously as they are going to need to be loaded immediately. Needlessly loading things asynchronously will actually slow your overall application down!

Exclusive

The exclusive split points are completely self-contained and can be loaded at any time. You want to have as many of these split points as possible, but at the same time you do not want them too tiny (e.g. a minimum size of 1000 bytes) and you do not want them too large (e.g. a maximum size of 50000 bytes). Also be careful of what happens to the leftover split point (see below) as you make more exclusive split points. You may see this growing very large, very quickly

Leftover

The leftover split point is interesting. It is not loaded at start-up but is completely loaded when the first exclusive split point is loaded. The left-over split point contains synchronous code that is referenced by two or more exclusive split points. This is the principle reason why I say the split point loading is not very sophisticated in this particular area. Suppose you have 20 exclusive split points and two of them make use of a large chunk of common code. This means it will be in the leftovers split point so it will be loaded as soon as any exclusive split point is loaded (even if that split point is not using the common code).

You definitely want to make the leftover split point as small as possible but sometimes it is impossible to make it any smaller. So long as you understand why this is then you will not waste your time trying to reduce it. Hopefully the DateBox wrapper example will help you to understand what is going on.

 

Put everything in one call

The key thing to understand is that every interaction with the exclusive split point must be completely self-contained in one function call. In general you can feed in input data (during the object creation) but it is difficult to get output data unless you are prepared to work with asynchronous concepts. In general these concepts are either events or call back functions. In this example, I show you how to wrap the DateBox control, so that it behaves like a synchronise control but is actually asynchronous in its internal implementation. We use events in this example. The code pattern we want to support is the following

void createDateBox(){

  MyDateBox dateControl = new NavWinAsynchDateBox();

  HorizontalPanel panelControl = new HorizontalPanel();

  panelControl.add(dateControl);

  dateControl.setValue(new Date());

}

 

void someEventHandler(){

  Window.alert(“” + dateControl.getValue());

}

 

Declare the class

Normally, if you extend a control you use the extends keyword e.g.

public class MyDateBox extends DateBox

For asynchronous loading you must not do this as you will be indirectly creating the control synchronously, whenever you create an instance of MyDateBox. The DateBox creation must occur in the asynchronous code later on.  The correct declaration pattern to use is this.

public class NavWinAsynchDateBox extends HorizontalPanel

{

       private DateBox _dateBox = null;

       private Date _currentDate = null;

}

In the above example, we assume that the HorizontalPanel will be loaded in the initial load in any case, as it is so fundamental to the GWT GUI. You are therefore free to use it anywhere in the code.

Declare the synchronous functions

Now we want to declare two functions that allow us to set the control date and get the date back. Note these are synchronous functions and therefore they cannot directly access any part of the DateBox control interface, otherwise the entire DateBox will be forced into the left-overs section or initial load.

public class NavWinAsynchDateBox extends HorizontalPanel

{

...

       private Date _currentDate = null;

      

       public void setValue(Date date)

       {

              _currentDate = date;

       }

       public Date getValue()

       {

              return _currentDate;

       }

}

 

Create the DateBox asynchronously

We are now ready to create the actual DateBox control. We can either use a dedicated synchronous method, or for simplicity, we will reuse the setValue() method as this is the only access function we intend to use which actually accesses the underlying DateBox.

public void setValue(Date date, String width)

{

       _currentDate = date;

       final NavWinAsynchDateBox finalThis = this;

       final String finalWidth = width;

 

       GWT.runAsync(new RunAsyncCallback() {

          public void onFailure(Throwable caught) {

            NavWinClient.Client.DisplayError("Download code - DateBox");

          }

 

          public void onSuccess() {

 

                if (_dateBox == null)

                {

                       finalThis.CreateDateBoxWithEventHandlers();                          

                }

                _dateBox.setValue(_currentDate);

                if (!finalWidth.equals(NavWinMessage.EMPTY_STRING))

                {

                       _dateBox.setWidth(finalWidth);

                }

          }

         

        });

}

 

The event handlers are set up in the function CreateDateBoxWithEventHandlers() below. Notice it is the fact that the change event handler sets a class level variable (_currentDate) to the current contents of the DateBox that allows the getValue() to work later on without accessing the DateBox itself. Also note we override the default display of the date box in order to remove the time element. If you want to use the default date and time display used by the date box then you can delete the whole block _dateBox.setFormat() {…}

private void CreateDateBoxWithEventHandlers()

{

       _dateBox = new DateBox();

       this.add(_dateBox);

       _dateBox.addValueChangeHandler(new ValueChangeHandler<Date>(){

 

       @Override

       public void onValueChange(ValueChangeEvent<Date> event) {

              // TODO Auto-generated method stub

              _currentDate = event.getValue();

              }

       });

        

       _dateBox.setFormat(new DateBox.Format() {

              @Override

              public String format(DateBox dateBox, Date date) {

                     return FormatDate(date);

              }

 

              @Override

              public Date parse(DateBox dateBox, String text, boolean reportError)

              {

                     return ParseDate(text, new Date());

              }

 

              @Override

              public void reset(DateBox dateBox, boolean abandon) {

                     // TODO Auto-generated method stub

                          

              }

       });

}

 

The left-over code

Although the above implementation makes a very big saving, it is not perfect because the DateBox makes use of other controls such as the PopupPanel. Because I use the PopupPanel in other parts of my application then this forces the PopupPanel to be in the left-over code. There is nothing I can do about this because the DateBox implicitly uses the PopupPanel and I cannot change this, without writing my own DateBox. It also using things like the CustomButton control which also appears in the left-over segment.

However at the end of the day it is all about balancing trade-offs of effort versus payback. For sure, my application, the way it is right now, loads very fast on a good broadband connection. Therefore I do not spend much time worrying about saving any more bytes in either section right now.