views:

281

answers:

9

I have the following code:

tr = document.createElement("tr");
root.appendChild(tr);
td = document.createElement("td");
td.appendChild(document.createTextNode("some value"));
tr.appendChild(td);

Well, this code is same as

root.innerHTML = "<tr><td>some value</td></tr>";

The first version is probably a better way to go, because the browser does not have to render a string. But it is too long. Especially for bigger structures, this implementation is becoming really hard to read. So I felt like there is a better way to write this (without any JavaScript library). How would you implement this so the code would be more readable? (Right now I am separating code with comments.)

A: 

innerHTML was originally an IE thing, I believe.

I also think you set it, as it is not a method, so that second example would be

root.innerHTML = "<tr><td>some value</td></tr>";

But to answer your question, innerHTML is more convenient, but it is often said to be slower. However, KennyTM says in the comments that it is much faster.

You have to decide if the performance trade off, which may probably be negligible, is worth doing it the DOM API way or the innerHTML way.

alex
A: 

Use jQuery http://jquery.com/

$('#root tbody').append('<td><td>some value</td></td>');

It will even use the proper DOM methods.

EDIT: From the jQuery docs:

jQuery is a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, animating, and Ajax interactions for rapid web development. jQuery is designed to change the way that you write JavaScript.

** EDIT:** Also, I made the sample above a little more HTML conformant @koby ;)

Matt Williamson
"Use jQuery" to questions about JavaScript not tagged jQuery are generally frowned upon. No downvote from me however... read [Bobince's](http://stackoverflow.com/users/18936/bobince) [enjoyable article](http://www.doxdesk.com/updates/2009.html) :)
alex
+1 because jquery is only short way to do this
Pranay Rana
@June R Is it worth including a 24kB library to save a handful of characters? What is wrong with `root.innerHTML = "<tr><td>some value</td></tr>";`?
alex
-1. I wouldn't vote it down, if you'd care to explain *what* jQuery does internally (and why).
Boldewyn
@alex -- jquery not only do this but it can do more bigger than this and it time to move on from normal javascript -- if you are talking about size of 24kb by including this long javascript in your file it increasing size of your file -- which may lead to more than 24kb in future -- so my opt is better to go for the jquery rather than javascript
Pranay Rana
I am writing a utility which could be added to any website. So I do not want to use any library. jquery way is probably a lot slower than innerHTML, because1) $('body') queries dom2) append method is probably doing some type checking inside.(it probably using innerHTML itself)
yilmazhuseyin
There's nothing wrong with recommending a framework to get the job done. In fact, reinventing the wheel is also "frowned upon" in our business, depending on how much JavaScript you need (jQuery will probably prove useful enough for more tasks). Now, appending a `<tr>` to `<body>` - that one in inexcusable `:)`
Kobi
@June R Sure it can do more, but when did the OP say he needed to do more? Also, I wouldn't say it is time to move on from native JavaScript. Libraries have their place (and I use them in 95% of projects), but knowing native JavaScript is a valuable skill to have. You can never be too reliant on a library (I know this from experience). It annoys me I need to use the phrase *native* JavaScript now.
alex
@Kobi: It's not about recommending a framework, it's about understanding *how it works* or *how it could be improved*. Correct me, if I'm wrong, but wasn't that the OP's question?
Boldewyn
@yilmazhuseyin: The jQuery way is not necessarily slower. In fact, I'm pretty sure, that the guys look extremely after performance. And they also do `innerHTML`, if it works for them: http://github.com/jquery/jquery/blob/master/src/manipulation.js
Boldewyn
jQuery actually makes operations like `append()` slower than either `innerHTML` or DOM methods, because internally it uses both. It creates a temporary wrapper element, sets `innerHTML` on it and then moves each node one by one into the target element (which involves two childNodes lists so is slower than normal appendChild). There are browser-compatibility reasons why you have to do this in some cases, but jQuery slows every operation down to that worst-case scenario. Also the business it does with regex-hacking the incoming markup is simply appalling.
bobince
@Boldewyn - you are correct. The discussion seems to have drifted away from the question.
Kobi
I added a description I snagged from the jQuery website.
Matt Williamson
A: 

I would have reordered to make it more readable

var d = document;
td = d.createElement("td");
tr = d.createElement("tr");
td.appendChild( d.createTextNode("some value") );
tr.appendChild(td);
root.appendChild(tr);
Codler
+2  A: 

innerHTML is definitely faster than DOM (see discussion section). Some time ago, I came across a way to conveniently write large HTML structures with innerHTML, it's a little better that string concatenation, or having to write large structures:

var html = [
   '<ul class="myclass">',
      '<li class="item">item1</li>',
      '<li class="item">item2</li>',
      '<li class="item">item3</li>',
      '<li class="item">item4</li>',
      '<li class="item">item5</li>',
   '</ul>'
].join("");

root.innerHTML =html;
naikus
You need to set the property; `innerHTML` is [not a method](http://jsbin.com/ususi3/).
alex
@alex Thanks a lot, it was a typo :D
naikus
+4  A: 

You could always write wrapper functions around the clunky DOM API to make the code more readable. I usually use something like:

function newElement (type,attr,children) {
    var el = document.createElement(type);
    for (var n in attr) {
        if (n == 'style') {
            setStyle(el,attr[n]); /* implementation of this function
                                   * left as exercise for the reader
                                   */
        }
        else {
            el[n] = attr[n];
        }
    }
    if (children) {
        for (var i=0; i<children.length; i++) {
            el.appendChild(children[i]);
        }
    }
}
function newText (text) {
    document.createTextNode(text);
}

Then your can write much more declarative code:

var tr = newElement('tr',{},[
    newElement('td',{},[
        newText('some value')
    ])
]);

Just remember the differences between css and javascript:

var div = newElement('div',{
    className:'foo',
    style:{
        marginLeft:'10px'
    }
},[
    newText('notice we use "className" instead of class" '+
            'and "marginLeft" instead of "margin-left"')
]);
slebetman
A: 

As I've mentioned in the comment, innerHTML is actually faster than creating DOM nodes, but it is unstructured.

A faster method than creating DOM nodes, but still structured, is to use the DOM 2 table methods:

var tr = root.insertRow(-1);
var td = tr.insertCell(0);
var txt = document.createTextNode("some value");
td.appendChild(txt);
// or simply: td.innerHTML = "some value";
KennyTM
A: 

I wrote some tests myself that compares innerHTML and the DOM API. The DOM API was definitely faster.

Here are the results (I have tested on Firefix 3.6.8 and Chrome 5.0.375.125 beta): http://yilmazhuseyindevelopment.appspot.com/ois/images/ahh5aWxtYXpodXNleWluZGV2ZWxvcG1lbnRyEQsSCUltYWdlRGF0YRiptwUM

In the first test, I added one textnode to body of page 1000 times with the DOM API and innerHTML.

In the second test I created a table with the DOM API and inner HTML. Here is the actual code for my test:

<html>
    <head>
        <script type="text/javascript">
        window.onload = function(){
            var body = document.getElementsByTagName("body")[0];
            var text,table,tr,td;
            var count = 1000;
            console.time("DOM");
            for(var i = 0 ; i<count ; i++){
                    text = document.createTextNode("text");
                    body.appendChild(text);
                    body.removeChild(text)
            }
            console.timeEnd("DOM");
            console.time("innerHTML");
            for(var i = 0 ; i<count ; i++){
                body.innerHTML = "text";
                body.innerHTML = "";
            }
            console.timeEnd("innerHTML");
            //table structure
            console.time("DOM2");
            for(var i = 0 ; i<count ; i++){
                    table = document.createElement("table");
                    tr = document.createElement("tr");
                    td = document.createElement("td");
                    text = document.createTextNode("text");
                    table.appendChild(tr);
                    tr.appendChild(td);
                    td.appendChild(text);
                    body.appendChild(table);
                    body.removeChild(table);
            }
            console.timeEnd("DOM2");
            console.time("innerHTML2");
            for(var i = 0 ; i<count ; i++){
                body.innerHTML = "<table><tr><td>text</td></tr></table>";
                body.innerHTML = "";
            }
            console.timeEnd("innerHTML2");
        }
        </script>
    </head>

    <body/>
</html>

I guess that means the DOM API is better (performance wise) for modern browsers.

yilmazhuseyin
A: 

Did you try to use a JavaScript templating engine?

They generally inject HTML strings by innerHTML and are way faster than DOM manipulations in both desktops and mobiles while keeping a separation between view and logic.

We use PURE which totally separates the HTML markup and the JavaScript logic. Designers and developers can work together on the same sources.

If you don't like it, you can find plenty of others on the web that may better suit your taste.

Mic
Unfortunately I cannot use this I am writing a tool myself. so I dont really know what kind of resulting structure I will have. And since my app is a utility, I don't want to add any dependency to my code. I decided to go with pure js. but templating engines look promising, I can use them in setting pages. thank you for the advice
yilmazhuseyin
It is very difficult to measure raw speed on small examples. A lot of parameters makes it hard(javascript is running when you measure, browser versions and quirks, depends on the type of content,...). We started our web app with DOM as it was more elegant but when the page started to be crowded, it was too slow for a productive environment and we used a templating engine. I think the innerHTML injection is not a very different logic than the browser receiving HTML from a web server.
Mic
A: 

Hey, I'm late to the game on this one, but wanted to add this information for you all. During some mobile browser development this issue came up for me, and wanted to see for myself which is better these days.

On my Android phone here's some interesting results:

      DOM: 614 / 25
innerHTML: 697 / 542
      DOM: 546 / 18
innerHTML: 639 / 552
      DOM: 604 / 12
innerHTML: 641 / 534
      DOM: 619 / 11
innerHTML: 643 / 554
      DOM: 618 / 13
innerHTML: 655 / 600

The first number is the actual execution of adding 2700 li elements. And, even more interesting is the second number, which is how long it takes the ol to flush out those results using innerHTML = '';

Try for yourself at DOM vs innerHTML.

Mister Lucky