Rendering web pages with flyweight pattern
Developing web applications using GWT is great. It connects you to all the useful Java tools out there and helps you be productive. Sometimes you even forget you’re programming against browsers because GWT does such a good job abstracting the subtlety of writing cross-browser compatible javascript code. However, GWT does not make the browser run fast.
One of the problems we solved recently here was that displaying items on one of the pages was extremely slow, especially on “one of the most popular web browsers”. The page displays 50 items at once, and each item displays a picture, title, details, three tags, and some meta data. We profiled the page and found that rendering 50 items in browser took around 1300ms, which consumed most of the time in the round trip. How can we improve that we thought?
In the original implementation, to display each item, a dozen of widgets need to be created. However, creating hundreds of Javascript objects is terribly slow and unnecessary. So our first try was to only create the widgets once then reuse them. We re-implemented some of the widgets that were immutable and only took parameters through their constructors. The fix did amortize the cost of display the paging, but it didn’t solve the problem for the first user access.
What if, instead of creating 50 items at once, we create just one item? This is where flyweight pattern came in. We improved the implementation of the item widget so that it works with a StringBuilder and builds the HTML string we put in a div element. Thus, we avoided creating a bunch of similar objects and ended up with rendering 50 items in 60ms, which is 20 times faster than the original implementation!
But we aren’t finished yet! The HTML string is put in a div element without calling the attach method. So basically, it is not listening to any of the DOM events happening to it. The rest of the challenge is how to handle the DOM events and user interactions. Since the events are bubbling up along the DOM tree, we came up with the idea to catch events on the wrapping div. Furthermore, we retrieve the element where the event was triggered from the native GWT event and apply proper css styling on it to show the user interaction. Note that using this technique requires code to deal with DOM elements that GWT usually shields from developers. More attention needs to be paid to the abstraction of the “dirty” lower level code so that everyone else on the team can understand and reuse it elsewhere.