Sencha Inc. | HTML5 Apps

DomHelper Performance

Published Feb 15, 2009 | Jack Slocum | Tutorial | Easy
Last Updated Jul 11, 2011

This Tutorial is most relevant to Ext JS, 2.x, 3.x.

This article is currently due for review
We suspect that this article may be out-of-date or contain incorrect information.
But we are constantly editing articles, so we promise we will get to this one soon.

If you are doing JavaScript development, then at some point or another you have probably had to use DOM to create elements. Like everything else with DOM, creating elements can be extremely verbose, leading to bloated code and spending too much time doing something that should be simple.

Creating elements using DOM can also have poor performance, especially in Internet Explorer. To maximize performance and maintain standards, any DOM creation classes should support both DOM and HTML fragments. HTML fragments are extremely fast in Internet Explorer, sometimes as much as 300% faster.

The DomHelper class provides a layer of abstraction from DOM and transparently supports creating elements via DOM or using HTML fragments. It also has the ability to create HTML fragment templates from your DOM building code.

Simple Examples

To save me from typing it out every time, the examples below are going to assume that a shorthand variable dh has being defined for Ext.DomHelper.

var dh = Ext.DomHelper;

Let's look at a simple example:

// The context element 'my-div' can either be the id or the actual node
 
var list = dh.append('my-div', {tag: 'ul', cls: 'my-list'});

Since DomHelper transparently uses DOM or HTML fragments, it manages appending the elements as well. This is a nice feature since it will save you from having to manually append everything after creating it. Let's expand the example:

var list = dh.append('my-div', {
     tag: 'ul', cls: 'my-list', children: [
          {tag: 'li', id: 'item0', html: 'List Item 0'}, 
          {tag: 'li', id: 'item1', html: 'List Item 1'}, 
          {tag: 'li', id: 'item2', html: 'List Item 2'}, 
          {tag: 'li', id: 'item3', html: 'List Item 3'}, 
          {tag: 'li', id: 'item4', html: 'List Item 4'}
      ]
});

All attributes on the passed object "o" are assumed to be element attributes, except for 4 special attributes:

  • tag - The tag name of the element
  • children - An array of the same kind of element definition objects to be created and appended. These can be nested as deep as you want.
  • cls - The class attribute of the element. "class" is a reserved word and className is too long. This will end up being either the "class" attribute on a HTML fragment or className for a DOM node, depending on whether DomHelper is using fragments or DOM.
  • html - The innerHTML for the element.

Here's a list of the insertion methods supported:

  • append (<HTMLElement/String> el, <Object> o) - Creates new DOM element(s) defined by o and appends them to el
  • insertBefore (<HTMLElement/String> el, <Object> o) - Creates new DOM element(s) defined by o and inserts them before el
  • insertAfter (<HTMLElement/String> el, <Object> o) - Creates new DOM element(s) defined by o and inserts them after el
  • overwrite (<HTMLElement/String> el, <Object> o) - Creates new DOM element(s) defined by o and overwrites the contents of el with them
  • createTemplate (<Object> o) - Creates a template from the DOM element(s) defined by o (See below)
  • insertHtml (<String> where, <HTMLElement> el, <String> html) - Inserts fragments into the DOM. It supports four insertion points related to el (which are named after the same points in IE's insertAdjacentHTML): beforeBegin, afterBegin, beforeEnd, afterEnd.

What's so special?

OK, I've seen this before. What's so special about this implementation?

Under the hood when you are creating your elements, DomHelper will transparently create HTML fragments when it can. Using HTML fragments instead of DOM can significantly boost performance. If you don't like performance boosts and you want to force it to use DOM, you can:

Ext.DomHelper.useDom = true;

The real power is in the built-in templating. The "o" parameter for createTemplate() has the same syntax as all the other methods only it doesn't create or append any elements. Instead it returns a Template object which can be used over and over to insert new elements. Let's revisit the example above, and use a template this time:

var list = dh.append('my-div', {tag: 'ul', cls: 'my-list'});
 
var tpl = dh.createTemplate({tag: 'li', id: 'item{0}', html: 'List Item {0}'});
 
for(var i = 0; i < 5, i++){
    tpl.append(list, <i>);
 
}

Template objects support the same insertion methods of DomHelper. The 2nd parameter to the insertion methods is either an array (for numeric template parameters, like the above example) or an object (for named parameters). The Template object can also be used on it's own:

var html = '<a id="{0}" href="{1}" class="nav">{2}</a>';
 
var tpl = new Ext.DomHelper.createTemplate(html);
tpl.append('blog-roll', ['link1', 'http://www.extjs.com/', "Jack's Site"]);
 
tpl.append('blog-roll', ['link2', 'http://www.dustindiaz.com/', "Dustin's Site"]);

Here's the same example using named parameters:

var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
 
var tpl = new Ext.DomHelper.createTemplate(html);
tpl.append('blog-roll', {
    id: 'link1', 
    url: 'http://www.jackslocum.com/', 
    text: "Jack's Site"
 
});
tpl.append('blog-roll', {
    id: 'link2', 
    url: 'http://www.dustindiaz.com/', 
    text: "Dustin's Site"
 
});

Compiling Templates

It's probably not shocking that the templates are applied using regular expressions. The performance is great, but if you are adding a bunch of DOM elements using the same template, you can increase performance even further by "compiling" the template. The way "compile()" works is the template is parsed and broken up at the different variable points and a dynamic function is created and eval'ed. The generated function performs string concatenation of these parts and the passed variables instead of using regular expressions.

var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
 
var tpl = new Ext.DomHelper.createTemplate(html);
tpl.compile();
 
//... use template like normal

Benchmarks

I did some benchmarking while creating these classes to see how different things would perform. I executed the code below in a loop 1000 times, which creates and appends 3000 new elements. I also had a non-template version which built the exact same thing.

var spec = {
    tag: 'div',
    style: 'width:100%;border:1px solid blue;',
    cls: 'wtf', 
    children: [{
        tag: 'a',
        href: '{url}',
        children: [{
            tag: 'span',
            html: '{text}'
        }]
    }]
};
 
var template = Ext.DomHelper.createTemplate(spec);

Below are the average times by browser. Notice the HUGE difference in IE6, 1.35 to .300. The DOM implemenation in IE6 must be written in VB with that performance ;) . Opera 9's performance creating nodes is amazing as usual.

Insertion MethodIE7 beta 2IE6FF 1.5Opera 9
DOM.7301.35.420.280
HTML Fragments.360.380.400.260
Template.320.335.385.220
Compiled Template.295.300.350.210
Share this post:
Leave a reply

Written by Jack Slocum

Commenting is not available in this channel entry.