Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript: Appending children to element

Which technique below is better from a user experience?

In both examples, assume that thumbContainer is set to the return value of document.getElementById('thumbContainer'), and new Thumbnail(thumb).toXMLString() returns a string with XHTML markup in it.

A) Simply += with thumbContainer.innerHTML:

for (thumb in thumbnails) {
    thumbContainer.innerHTML += new Thumbnail(thumb).toXMLString();
} 

B) Or converting new Thumbnail(thumb).toXMLString() to DOM elements and using appendChild?

for (thumb in thumbnails) {
    var shell = document.createElement('div');
    shell.innerHTML = new Thumbnail(thumb).toXMLString();
    for (i = 0; i < shell.childElementCount; i++) {
        thumbContainer.appendChild(shell.children[i]);
    }
}

I've used both and get complaints from Firefox that I've got a long-running script, and do I want to stop it?

Which loop is less-tight, that will allow the UI to update as new elements are added to the DOM?

like image 698
ChrisOh Avatar asked Feb 13 '10 10:02

ChrisOh


2 Answers

A) Simply += with thumbContainer.innerHTML

Never do this. This has to serialise all the content to HTML, add a string to it, and parse it all back in. It's slow (doing it in a loop is particularly bad news) and it'll lose all JavaScript references, event handlers and so on.

IE's insertAdjacentHTML will do this more efficiently. It's also part of HTML5, but not widely implemented elsewhere yet.

using appendChild?

Yes, that's fine. If you've got a lot of thumbs it will start to get slow (but not as bad as reparsing innerHTML each time). Making a DocumentFragment to insert multiple elements into the container child node list at once can help in some cases. Combining DocumentFragment with Range can do more still, but gets harder to write compatibly since IE's Range implementation is so StRange.

Either way, since you don't seem to be doing anything with the individual shell nodes, why not simply join all the thumbernail HTML strings together before parsing?

for (var child in shell.childNodes) {

Don't use for..in on sequence types, it won't do what you think. It's only meant for use against Object used as a mapping. The correct way to iterate over an Array or NodeList is plain old for (var i= 0; i<sequence.length; i++).

like image 132
bobince Avatar answered Oct 21 '22 13:10

bobince


Personally I like the second approach (using appendChild) better, because, you are adding new element to the document tree without affecting the old elements.

When using innerHTML += new content, you affect old content, because all the HTML has to be reassigned (replaced with new HTML that contains of old code and some new code).

But, if you want to increase the performance, I'd suggest using DocumentFragments. Using them you can append a whole set of nodes with just one appendChild call on the document tree. Worth reading: "DOM DocumentFragments" by John Resig, but it's not the case in your problem, because you get the content as a string, that you have to first convert to DOM nodes.

My second suggestion is, to create a string of HTML code and then use innerHTML on a temporary container to convert it to DOM nodes

var htmlCode = "";
for (thumb in thumbnails) {
    htmlCode += new Thumbnail(thumb).toXMLString();
}
var element = document.createElement(htmlCode);
element.innerHTML = htmlCode; // ... and append all the elements to document, or thumbContainer.innerHTML += htmlCode;
like image 44
Rafael Avatar answered Oct 21 '22 11:10

Rafael