Authors: Renat Akhmerov, Alexey Kharlamov
Since the public introduction in August of 2006 the Google Web Toolkit (GWT) has gained significant momentum among web developer. The technology allows to build very interactive and responsive applications using convenient and very sophisticated tools as Eclipse, Maven and SVN. Moreover the GWT aims to build cross-browser applications by isolating platform specific quirks.
Our team has used Google Web Toolkit since the 1.1 release. While we are very happy with overall development experience we have found several performance limitations of the library. Actually, the limitations originate from restrictions inherited from the HTML layout algorithms and browsers implementations. In this article we will try to offer ways to workaround these limits by using more effective ways of HTML manipulations.
First of all, let me describe our application. The system is aimed to provide time management and collaboration features to the system members. So the most time a user sees a tree of tasks like Work Breakdown Structure. GWT components worked rocket-fast while the number of visible items did not start to grow. Some of active users had several thousands of items in their space. So the rendering took tens of seconds.
Any long running work should be divided into small-to-medium sized chunks and executed through the DeferredCommand. So a parallel execution is emulated.
Fig. 1 Deferred rendering
While we are keeping execution time of a single DeferredCommand less than 100-200ms delays between user actions and system reaction do not hurt user experience. But the solution is not exhaustive. It softens the problem, but rendering of complex data still may be too long. The problem is hidden inside component model provided by the framework.
GWT has many special widgets that serve as containers. Frequently the containers are used to format other components with data attributes. It turned out that containers used DOM.appendChild() method to attach their children to a document. For example, FlexTable and VerticalPanel manage descendants this way. Also, the standard components actively use DOM.createElement() calls. These operations are fast enough for a small number of components. However, they are really slow in a mass.
Our tests had shown that DOM.setInnerHtml() worked much faster than the DOM.createElement()/DOM.appendChild() pair. This is quite expected as innerHtml property uses optimized native DOM building code inside the browsers. So we decided to rework our Tree component to use innerHtml. The updated tree was hundreds times faster! It seems dynamic operations on DOM inside browsers are far from optimal in the most wide-spread browsers. To resolve the issue we abstracted a common way to implement UI components those should be rendered quickly and called it FastContainer.
The FastContainer pattern
The idea of the pattern is simple. Using setInnerHhtml to create DOM fragments and attach GWT components to the appropriate elements. But it’s not very convenient way to work with DOM-objects representing them as strings. Moreover, setInnerHtml is more effective for bigger chunks of HTML code. So it is sensible to insert a group of elements/components at once.
Fig. 2 Work item
If you take a look at the picture above you will see an example of such group. This component can be virtually divided into layout HTML and a set of controls (one checkbox and the text labels in this case).
Under layout we understand the frame with gray background and rounded corners. It contains other small controls inside. The layout is also responsible for alignment of these controls in its scope. So if we want to implement this layout using most common way we’ll have to do a lot of things. First, we’ll need to create an instance that will be a layout. For example, it is possible to use FlexTable or some other panels. Then we’ll have to do complete configuration of this object adding all the rows and cells (including cells that will contain pictures of rounded corners), setting styles up for these cells, inserting pictures of rounded corners and then inserting target controls. All of these actions would be performed dynamically step by step! And each will call one or several createElement()/appendChild() methods. But this can also be accomplished using text representation and a single call to the DOM.setInnerHtml() method. And the layout HTML can be developed in a favorite editor rocket-fast.
Following this logic FastContainer pattern was invited to provide a convenient way to work with components considering them as HTML fragments. In other words, this pattern allows building a Widget instance from html text fragment and provides an interface to interact with the contained widgets. The original idea belongs to Sergey Dryganets who suggested the abstraction and provided the first implementation called LightWidget. Later we improved it and formulated the FastContainer pattern.
The basic idea is isolation of HTML source inside a Pattern entity. The entity encapsulates all HTML source building logic. The class FastContainer represents a desired component that builds itself using pattern and context. Also it provides an interface required to manipulate with its descendants.
On rendering stage each FastContainer uses the Pattern to generate an HTML fragment which is passed to browser. During the generation process the ConcretePattern instance fills the Context with data about element bindings. So the container will be able to quickly find required elements.
Fig. 3 FastContainer structure
It is very important to understand that the Context is a bridge between the container and its representation inside the browser’s DOM. It allows perform dynamic updates of internal structure and quickly find placeholders for child components insertions.
As there can be several instances of the same pattern inside the document an IdManager should be used to generate unique IDs for HTML placeholders. But this process is completely hidden in the pattern implementation. So client is only aware of names (string values or any other keys) of the placeholders. Using these names a client can:
· put a plain text/HTML code into the specified placeholder
· put a Widget into the predefined position in the pattern
· create a Widget descendant using an element inside the pattern
Pros and cons
Using this pattern we have two advantages. First, we have the possibility to implement layout of some component as an html code. That is more straightforward way than using GWT object model. The second advantage is in improving rendering speed of the component due to using DOM.setInnerHtml() and the fact that we attach the component’s layout in one step instead of building it iteratively in a few steps.
However, GWT encapsulates the most serious cross-browser issues. As we use pure HTML we are in charge of solving cross-browser problems by hand now.
Also it is inconvenient to manage generation of the HTML code inside Java sources. While there are some methods to relax the problem by using external HTML templates (See GWT HtmlTemplate widget), they may slow down application loading and rendering speed.
At the moment we see only one satisfactory solution. A support of HTML pattern generation inside the GWT compiler in a manner of resource bundles implemented now. This will allow:
· avoid manual generation of patterns together with all id related work
· improve performance
We would be happy to discuss ways of the GWT compiler improving with the community.
Do you like the article and want us to develop your project? Feel free to contact us here!
This entry was posted on Wednesday, February 13th, 2008 at 8:21 am and is filed under gwt.