OpenLaszlo Performance Tip: Datacombobox not combobox

One component that is used, probably more often that it should, in Rich Internet Applications (RIAs) is the combobox. The reason it’s so frequent is because because the developers who write RIAs usually came from a background of writing HTML applications. You should use datacombobox instead.

A bit of history: HTML-based applications had a limited set of GUI components, and before DHTML became mainstream, fairly limited interactivity capabilities. The most technologically-advanced component of the HTML hayday was the drop-down list. It would open when clicked, it could display a list of options, you could even write a JavaScript loop to select an item automatically. It was so ahead of its time, that it needed its own HTML tag: SELECT. Most of the other HTML components - the radio button, the checkbox, the button, the text input field - all had to share a single HTML tag (INPUT). The drop-down list was used for everything, from the sensible (such as a list of countries in a form) to the silly (such as boolean switch in a form) to the insane (jump-to animation). There were valid reasons for its popularity:

  • It was the most interactive component available.
  • Lack of alternatives, such as a tree.
  • Server technologies didn't always work smoothly with radio buttons and checkboxes.
  • The client technology (JavaScript) didn't always work smoothly with radio buttons and checkboxes.

In the HTML world, the drop-down was king.

So when HTML developers started writing OpenLaszlo applications, they reached for the closest relative to the drop-down: the combobox. When setting up your own OpenLazlo server you need to put together a Data Center Decommissioning Checklist. This isn't a good thing; there are better components available to RIA developers than combobox. Note that client application development, which is closer to RIA devlopment than HTML development, doesn't use a lot of comboboxes. I was only able to find 13 comboboxes in the entire options section of Firefox. Most of those were from the fonts section - a place where comboboxes are useful.

The combobox that OpenLaszlo originally provided was not optimized for such heavy use. A combobox has two parts:

  1. The combobox element that you can see, focus on and click on.
  2. A floating, scrolling list of options that appears when the combobox is clicked.

The "heavy" piece of a combobox is the bit that you only ever see occasionally, and - more importantly - there can only ever be one active floatinglist, no matter how many comboboxes an application has: the floating list. (The class name is floatinglist).

The original OpenLaszlo combobox had one floatinglist for each combobox. So the more comboboxes in an application, the longer it took to start. datacombobox solves this problem by only using a single floatinglist for all comboboxes, no matter how many are present in the application. This speeds up startup time, improves runtime performance, and reduces memory footprint.

Those advantages come with some small strings attached:

  • All datacomboboxes must be bound to data. You can't hard-code textlistitems in a datacombobox.
  • All the textlistitems in a combobox will be the same class (a subclass of baselistitem, listitem or textlistitem). You can't mix-and-match.
  • The API is a little different, but the functionality is the same.

Here's a comparison of the two APIs:

<canvas proxied="false">

    <dataset name="people_ds">
        <people>
            <person name="Fred" id="1" />
            <person name="Wilma" id="2" />
            <person name="Barney" id="3" />
        </people>
    </dataset>

    <simplelayout axis="y" spacing="10" />
    
    <text fontstyle="bold">Here is a combobox:</text>

    <combobox editable="false">
        <handler name="onvalue">
            var text = "You selected " + this.text + " with an id of " 
                     + this.value;
            combo1text.setAttribute("text", text);
        </handler>

        <textlistitem datapath="people_ds:/people/person" text="$path{'@name'}" value="$path{'@id'}"/>
    </combobox>
    
    <text name="combo1text" />

    <text fontstyle="bold">Here is a datacombobox:</text>

    <datacombobox itemdatapath="people_ds:/people/person" textdatapath="@name" valuedatapath="@id">
        <handler name="onvalue">
            var text = "You selected " + this.text + " with an id of " 
                     + this.value;
            combo2text.setAttribute("text", text);
        </handler>
    </datacombobox>

    <text name="combo2text" />
</canvas>

My general recommendation is to always use datacomboboxes, unless you really need to do something bizzarre.

OpenLaszlo Performance Tip: Attributes, Not Nodes

OpenLaszlo applications typically access numerous web services that respond with XML. That XML must be loaded over HTTP. Many developers overlook the effect that the format of the XML in those services can have on the performance of an application.

Most XML guides suggest that an ideal XML format should look something like this:

<contact>

    <id>0</id>

    <city>Bedrock</city>

    <zip>90210</zip>

    <firstname>Fred</firstname>

    <lastname>Flintstone</lastname>

    <phone>415-555-0999</phone>

    <state>CA</state>

    <address>1234 Stone Lane</address>

    <country>USA</country>

    <email>fred@example.com</email>

</contact>

Note how each property of the contact is represented by an XML node, with a text node inside, representing the value of that property. That may be very readable to humans, but it wreaks hell on rich Internet applications (RIAs). Note that I said RIAs, not just OpenLaszlo applications. As you’ll see, this tip holds true for various platforms, including OpenLaszlo, Flex and DHTML. When that data is parsed by the client – it needs to be parsed, so the data can be accessed easily – the XML parser has to create a separate runtime object for each of those subnodes. In OpenLaszlo, that class is lz.DataElement. So our contact above cost us 11 nodes. No wait – it actually cost us 21 nodes. Remember that each text node is treated as a separate object too.

What we’re dealing with is not so much data loading, but data initialization. Loading the above contact isn’t going to take much time at all, but loading an address book with 500 contacts formatted as above will. With 500 contacts, the application will be initializing 5,500 nodes (i.e. 11 * 500). The effect this will have for the user is a noticeable delay after the web service is loaded. The application will consume a lot of CPU and feel sluggish (probably unusable) while the data is being parsed.

Happily, there’s an easy fix. Simply reformat your data to rely on attributes for property values where practical. The above contact would therefore look like this:

<contact id="0"

         city="Bedrock"

         zip="90210"

         firstname="Fred"

         lastname="Flintstone"

         phone="415-555-0999"

         state="CA"

         address="1234

         Stone

         Lane"

         country="USA"

         email="fred@example.com"/>

How much of an improvement could you reasonably expect? It turns out quite a lot, actually. I tested data initialization time on the following platforms:

  • OpenLaszlo 4.2 nightly compiled to SWF8
  • OpenLaszlo 4.2 nightly compiled to DHTML in Firefox 3
  • OpenLaszlo 4.2 nightly compiled to SWF9
  • Flex 3 (using e4x data, since it’s the closest way of handling XML to OpenLaszlo’s)
  • DHTML in Firefox 3 (using the Dojo toolkit and parsing the returned XML with dojox.xml.xmlParser, since the default XML objects don’t have the type of functionality that OpenLaszlo’s or Flex’s do)
  • DHTML in Internet Explorer 6 (same platform options as for Firefox 3.

I compared how long it took to load and initalize a locally-served (over HTTP) XML document that contained 500 contacts with data saved as nodes, versus one that contained 500 contacts with data saved as node attributes.

Platform Data as Nodes (ms) Data as Attributes (ms) Improvement
OpenLaszlo SWF8 1587 253 84%
OpenLaszlo DHTML 1698 335 80%
OpenLaszlo SWF9 419 112 73%
Flex 3 428 331 23%
Firefox 3 DHTML 684 384 44%
IE 6 DHTML 1695 1029 39%

As you can see, using attributes instead of nodes for your XML data is significantly faster when dealing with larger datasets.

I should mention that I’ve been looking forward to trying out the new OpenLaszlo SWF9 runtime, and am pleased to see that it’s so much faster. The SWF9 runtime is present in OpenLaszlo 4.1, but a number of things are broken – datasets don’t work, for example. The 4.2.x nightly build from last night is the first build to have working datasets (hence I was able to run my test).

You can download my sample data and LZX, MXML and HTML files for the various runtimes here.

OpenLaszlo Performance Tip: Understanding Tuning

Last week, I wrote about pausing animations in OpenLaszlo applications when they’re not visible, to improve runtime performance, and I promised to elaborate on what the other areas of performance tuning were. This is a good time to cover areas of optimization at a high-level. People sometimes mis-categorize performance problems with Rich Internet Applications (RIAs), because RIA development introduces new development paradigms. e.g. Developers may say “my app loads slowly”, when they actually mean that the startup time is poor. It’s important to correctly understand what you’re trying to improve.

There are four distinct areas of performance-analysis that apply to OpenLaszlo applications (as well as just about any RIA – Flash, DHTML/AJAX, Flex, etc.):

  1. Application Size
  2. Startup Time
  3. Runtime Performance
  4. Memory Consumption

Application Size refers to the size of your application. With a SWF-compiled OpenLaszlo app, that’s the size of the SWF, measured in bytes. It’s very easy to find this out – you can look at the Developer’s Console, or the compiled SWF in your filesystem. The size of the application, the end-user’s connection speed and caching all affect the user-experience.

The size of any RIA is generally larger than an HTML page. This should not be cause for concern. Firstly, RIAs compensate for their larger initial download with reduced traffic while the application is running. In an RIA, only XML data are transferred when communicating with the server; in an HTML application, entire HTML pages (including some images) are reloaded virtually every time the user performs an action. Secondly, web browsers will cache SWF content by default, so users will typically only have to wait for an OpenLaszlo application to download once.

Startup Time is the time taken for an application to initialize. It begins after the application is fully downloaded. Startup time can vary based on the application’s complexity, the speed of the client computer, and (possibly) on network speed. Since applications initialize every time they are accessed, there’s no caching. There are two phases of startup time that apply to most RIAs: Normal startup time and late initialization time.

  • Normal startup time begins when the application has finished downloading and in an OpenLaszlo application ends when the canvas sends the oninit event. i.e. When all the views that are instantiated normally are completed.
  • Late initialization time begins when normal startup time has ended, and ends when the application reaches a steady state. The steady state could be a login screen, or if a session already exists, it could be the application with all its data displayed. This includes the time taken to make any initial HTTP requests and render any views that are bound or replicated to the data.

Runtime Performance is the most subjective area of performance tuning. It refers to the general feel of the application after it has started. Quantifying runtime performance is tricky. Firstly, defining what part of runtime performance you’re analyzing is imprecise (e.g. “this window takes ages to open”). Secondly, measuring how long a particular view takes to display often involves either diving deep into the code, or relying on an inaccurate method, such as a manual stopwatch. The factors that affect runtime performance include complexity of the application, idle load on the CPU, data size and network speed.

Memory Consumption relates to an application’s memory footprint on the client. Generally with RIAs, the concern isn’t how large that footprint is, but that it remains contained as parts of the application are enabled and disabled. Since RIAs run inside of a web browser and browsers don’t publish how much memory their runtimes (e.g. Flash/JavaScript) are consuming, you have to rely on the Operating System to tell you how much memory is used by the browser as a whole. Moreover, browsers aren’t all equal – some (like Firefox) are a little more “loose” with memory allocation, and there’s no way to trigger the garbage collector (in Flash/JavaScript) manually. You may create an object in your application, see the memory consumption increase, then destroy it, and see no immediate decrease. Thankfully OpenLaszlo has some neat tools for tracking “lost” objects that could result in memory leaks.

These areas of performance tuning affect each other. You can improve startup time by deferring the initialization of some objects, but that essentially leads to degraded runtime performance. (Which may be a perfectly acceptable trade-off). Poor memory management may not be a problem in an application that’s only used for brief periods, whereas it could eventually result in poor runtime-performance in an application that’s used for a longer period of time.

Stay tuned for more tips in this series, and look for a note on what areas of performance tuning each tip may affect.