The slower the web application loads and runs, the less users will want to use it. Google understands this more than anyone else, so the Web Toolkit they created focused on the speed of the web applications that it uses.
The article talks about what client optimization techniques are used in the GWT.
Separate version of the application for each browser
Each browser has its own characteristics, which in a certain way complicates the life of the developer. So, for example, to get an XMLHttpRequest object (necessary for making asynchronous requests to the server from JavaScript) in IE6, it is passed through to use ActiveXObject:
var xhr = new window. ActiveXObject ( "Microsoft.XMLHTTP" ) ;
All other (non-IE) browsers provide native support for the XMLHttpRequest object:
var xhr = new window. XMLHttpRequest ( ) ;
Usually (this is how most JavaScript libraries are arranged) in such situations all browser-dependent implementations are included in a web application, and in each particular browser they use only one of them, selecting it in the course of execution, that is, after they are loaded and disassembled into including unnecessary implementations.
Google Web Toolkit uses a different (in all senses) solution: for each browser, a separate version of the web application is assembled, called permutation. Each permutation contains everything that is needed to work only in one browser, so, for example, a “fire fox” will never have to download and parse JavaScript or CSS specific for IE.
')
Optimization, minimization and obfuscation
To speed up the loading of a web application, JavaScript and CSS are usually minimized, for example, using
YUI Compressor , which, by removing whitespace and other optional constructions, as well as obfuscation, significantly reduces their size.
The Google Web Toolkit also minimizes and obfuscates, but the input to the minimizer is JavaScript, not written by humans, but received as a result of the Java-to-JavaScript compiler. The compiler safely removes unused code, expands methods, optimizes polymorphic relationships, calculates constant expressions and does much more, resulting in an optimized (in size and speed) JavaScript.
A small (primitive) example:
public class CircleMath {
public static double getArea ( double radius ) {
return math PI * radius * radius ;
}
public static double getCircumference ( double radius ) {
return math PI * radius * 2 ;
}
}
...
double a = CircleMath. getArea ( 7.5 ) ;
double c = CircleMath. getCircumference ( radius ) ;
During compilation, CircleMath will be removed, its static methods will be replaced with inline-inserts, and mathematical expressions will be optimized. The result is the following javascript:
var a = 176.714586788 , c = 6.283185308 * radius ;
Optimized for better gzip compression
All modern browsers support compression, which (if properly configured web-server) can significantly reduce the size of the transmitted data. HTML, CSS and JavaScript are especially well compressed, decreasing on average by
75% .
These results, which are largely dependent on the data themselves, seemed unsatisfactory to Google’s engineers, so they modified the obfuscator included in Google Web Toolkit so that the resulting obfuscated code would always be compressed with Gzip as much as possible.
To see how this works, let's compress two lines using GNU Gzip:
a b c b a c a b c a b b b a c a b c
a a a a a a a b b b b b b c c c c c c c
You can see that both strings consist of the same number of identical characters, and differ only in the order of some of them, while after compression, the first line does not decrease by one byte, while the second line becomes shorter by 3 bytes. Similarly, if you change the order of the function declaration in JavaScript, so that the duplicate code is within the same “
sliding window ”, the script will be compressed
more than in the random order function declaration.
CSS sprites and embedded images (data: URL)
CSS sprites and
embedded images help reduce the number of server calls needed to load the web application's interface graphics. In most cases, it would be possible to confine one embedded image, but since they are not supported by some still widely used versions of IE, both techniques have to be applied.
For building the user interface, Google Web Toolkit allows you to use familiar technologies: HTML and CSS, a few of which extended syntax helps, without any additional effort and knowledge, to solve the problem of providing cross-browser image loading optimization:
<! DOCTYPE ui: UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui: UiBinder xmlns: ui = "urn: ui: com.google.gwt.uibinder" >
<ui: image field = "image1" src = "1.png" />
<ui: image field = "image2" src = "2.png" />
<ui: style >
@sprite .image1 {
gwt-image : "image1" ;
/ * ... CSS properties ... * /
}
@sprite .image2 {
gwt-image : "image2" ;
/ * ... CSS properties ... * /
}
</ ui: style >
<div >
<div class = "{style.image1}" > </ div >
<div class = "{style.image2}" > </ div >
</ div >
</ ui: UiBinder >
When building a web application that includes such a UI template, 1.png and 2.png will be combined into one image that will be used in permutations for IE6 and IE7 using CSS Sprites. In all other permutations, the original images will be embedded in the form data: URL. In both cases, all necessary properties will be added to the image1 and image2 CSS classes automatically.
Dividing an application into modules
The permutation mechanism of Google Web Toolkit allows modern browsers to download HTML, Javascript, CSS, and images — all the components of a web application — as a single file in one call to the server.
With the growth of the functionality of a web application, the size of permutations inevitably increases, and the time required for loading each of them increases accordingly. A moment may come when the “cold start” (browser cache is empty), even with all the possible optimizations, will start to take an unacceptably long time.
In this case, the Google Web Toolkit provides the ability to split the web application into several separately loadable modules. Thus, the main functions of a large application can be made available to the user immediately after loading a small start module, and the rest, providing additional functionality, can be loaded as required. Modules are created and loaded automatically; the developer only needs to specify the split points.
Using modules, the developers of Google Wave were able to bring the average load time of their offspring to a few seconds, although the total size of this “monster” is about 3 MB.