Archive for the 'Firefox' Category

Increasing appendChild Performance with DOM Tricks

Tuesday, July 22nd, 2008

A recent blog post by John Resig has outlined a performance sensitive method of appending many elements to your document. His suggestion, using DocumentFragment as the container object to which to append all child nodes, is backed by some pretty impressive benchmarks. The most drastic performance improvements by using this method of appending objects to the document are witnessed by Internet Explorer and Safari, IE6 improved by 65%, IE7 by 73% and Safari by 71%.

In looking at his code used to test this, some users argued that his test cases were slightly skewed as the container object was handled in two different manners. In the case using appendChild for each childNode, the container object was looked up on the gathered div array using the loops index to point to the value. Why not store it they asked? This led to accusations that in the case that switches to using the DocumentFragment, the benefit may be derived from the idea that the container object is accessed as a stored value inside the loop. This also lead to questioning that, in his second case, the majority of the content was being appended to an object not yet living in the DOM.

This begs the questions– Does the perceived performance increase being witnessed in this case come from the fact that the container object is detached from the DOM while being appended? I decided to dive in…

The Procedure

To do this, I set up three cases and tested in both Firefox 2 and Internet Explorer 7. Knowing that the original idea, looping through the divs and accessing the container as div[i], was the least desirable, I decided to toss that out the window from the get go.

For my first case, "Appending to Attached Div", I stuck with the structure of John's control case, in which the nodes are appended directly to an element still active in the DOM. The one tweak I did make, was to store a reference to the container div rather than using div[i]. This was as simple as setting var container = div[i] inside the first loop. This resulted in:

var div = document.getElementsByTagName("div");
   
    for ( var i = 0; i < div.length; i++ ) {
        var container = div[i];
            for ( var e = 0; e < elems.length; e++ ) {
                    container.appendChild( elems[e].cloneNode(true) );
            }
    }

Case 2 involved using John's DocumentFragment method verbatim. This presented an element of control to my test in relation to his.

In the 3rd case, I decided to use the method just like in case 2, however rather than using createDocumentFragment() I created a table element with createElement("table"). This was stored as the container to which to append the children elements.

var div = document.getElementsByTagName("div");
   
    var container = document.createElement("table");
    for ( var e = 0; e < elems.length; e++ ) {
            container.appendChild( elems[e] );
    }
   
    for ( var i = 0; i < div.length; i++ ) {
            div[i].appendChild( container.cloneNode(true) );
    }

My Results

The results are as follow, with time to execute represented (in seconds).

Appending to Attached Div Appending to Document Fragment Appending to Table
FF2 2.046 .430 .481
IE7 4.134 3.256 3.715

In Conclusion

After going through this test, I decided that John was definitely onto something. He found the most optimized way to approach this method. Between the two cases in which I appended the content to an object that was not yet in the DOM (for the elems array), the DocumentFragment method proved to be more efficient by about 10%. The one thing I would like to add–that I feel my test proved–is that when you are doing the majority of your appending, you should be doing it to an object that is not currently contained within the DOM. You can then later append that object to its destination container.

P.S. On a humorous note, the original case that John was using in his test took far too long for me to run with the sheer volume of div's I was trying to populate. In fact, it caused Firefox to prompt me to stop the script and Internet Explorer just locked up… Definitely make sure you use one of these presented solutions for appending nodes to improve your performance!

Valid Flash in Firefox

Saturday, January 13th, 2007

In working on getting Ryboe.com to correctly validate tonight, I ran across an interesting tidbit about Flash movies and the W3C. The <embed> tag was created by Netscape as a way to get Flash objects to play in their browser. The problem with this Netscape-invented <embed> tag is that the W3C does not recognize it as a valid XHTML tag. If you are like me and would like for your site to validate, you have to remove it. So how do you get your Flash files to play in Firefox, Netscape, etc. and still have your site validate? Well, after doing some digging, I found that the solution is actually quite simple.

In this case, I have an image slideshow Flash movie that I want to display. Here is what the HTML embed code used to look like to show the Flash:

<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="580" height="225" id="slideshow" align="left">
<param name="movie" value="slideshow.swf" />
<param name="quality" value="high" />
<param name="bgcolor" value="#ffffff" />
<param name="wmode" value="transparent" />
<embed src="slideshow.swf" quality="high" bgcolor="#ffffff" wmode="transparent" width="580px" height="225px" name="slideshow_as2" align="left" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
</object>

In this article, entitled Embedding Macromedia Flash While Supporting Standards, Drew McLellan talks about his experience in dealing with this exact issue.

Just strip the <embed> tag altogether and place an extra definition of the Flash file path within the opening <object> tag. A "type" attribute is used to define that you want the Flash movie to play with the Macromedia Shockwave-Flash player. Here is my final code:

<object type="application/x-shockwave-flash" data="slideshow.swf" width="560" height="225" id="slideshow" align="left">
<param name="movie" value="slideshow.swf" />
<param name="quality" value="high" />
<param name="bgcolor" value="#ffffff" />
<param name="wmode" value="transparent" />
</object>

By defining the path to the Flash file again with the "data" attribute, my movie plays fine!