21

I got this bad feeling about how I insert larger amounts of HTML. Lets assume we got:

var html="<table>..<a-lot-of-other-tags />..</table>"

and I want to put this into

$("#mydiv")

previously I did something like

var html_obj = $(html); $("#mydiv").append(html_obj);

Is it correct that jQuery is parsing html to create DOM-Objects ? Well this is what I read somewhere (UPDATE: I meant that I have read, jQuery parses the html to create the whole DOM tree by hand - its nonsense right?!), so I changed my code:

$("#mydiv").attr("innerHTML", $("#mydiv").attr("innerHTML") + html);

Feels faster, is it ? And is it correct that this is equivalent to:

document.getElementById("mydiv").innerHTML += html ? or is jquery doing some additional expensive stuff in the background ?

Would love to learn alternatives as well.

Julius Eckert
  • 1,481
  • 4
  • 16
  • 24

8 Answers8

33

Try the following:

$("#mydiv").append(html);

The other answers, including the accepted answer, are slower by 2-10x: jsperf.

The accepted answer does not work in IE 6, 7, and 8 because you can't set innerHTML of a <table> element, due to a bug in IE: jsbin.

gblazex
  • 49,155
  • 12
  • 98
  • 91
  • 1
    +1, building the html as a string and using a single 'append' instead of building each element using jquery increased the performance in my case by an order of magnitude (created 280 divs, each with a table, and a couple of rows, took 12 seconds, now it's down to 1.1). Although you might want to cut back on the insults... ;) – falstro Jan 11 '11 at 08:01
  • 1
    +1 for posting a jsperf.com link when that is exactly what's needed – Jens Roland Feb 16 '11 at 13:50
  • Your test is dishonest. It creates a new dom fragment for each element. you are suppose to append all of the elements to one dom fragment, then insert it into the dom tree. Here is a REAL test http://jsperf.com/scriptjunkie-premature-7 – Robert Hurst Jun 10 '11 at 03:23
  • 1
    @Robert: We don't moderate for technical accuracy. – Robert Harvey Jun 10 '11 at 04:33
  • @RHurst - What did you say mr? I presented the test cases from the OP's question and the accepted answer. There is **no dishonesty** in that. If you **read** the question, the OP wants to insert one chunk of **string as html** into the document. Your answer is completely off the road (adding *individual* elements). I'm sorry but you should **read** before claiming someone or his test to be dishonest. – gblazex Jun 10 '11 at 14:04
  • `innerHTML` on the other hand is a de facto industry standard, which gives you the greatest performance if that's what you're after. But if you got a large **html string** then's you don't even have a choice to use anything else (unless you want to parse the HTML of course). Thus if you're **incapable of reading the entire question** not just the title, then you have no right to be offended, sir... – gblazex Jun 11 '11 at 09:33
  • try `typeof "....
    "`
    – gblazex Jun 11 '11 at 09:43
  • 2
    @galambalazs , i added a new test case to your jsperf [test](http://jsperf.com/jquery-append-html/10). it builds the dom manually, which is the only real alternative to appending an html string. parsing is clearly bottleneck, and while the original question may not have been looking for this, i think there are others who would be interested in knowing how much faster it is if you're willing to build it manually. (it does answer the question of the title) – yincrash Aug 04 '11 at 01:54
  • @yincrash - Yes your test case has nothing to do with the OP's question, but at least you admit it. :) – gblazex Aug 08 '11 at 11:03
22

innerHTML is remarkably fast, and in many cases you will get the best results just setting that (I would just use append).

However, if there is much already in "mydiv" then you are forcing the browser to parse and render all of that content again (everything that was there before, plus all of your new content). You can avoid this by appending a document fragment onto "mydiv" instead:

var frag = document.createDocumentFragment();
frag.innerHTML = html;
$("#mydiv").append(frag);

In this way, only your new content gets parsed (unavoidable) and the existing content does not.

EDIT: My bad... I've discovered that innerHTML isn't well supported on document fragments. You can use the same technique with any node type. For your example, you could create the root table node and insert the innerHTML into that:

var frag = document.createElement('table');
frag.innerHTML = tableInnerHtml;
$("#mydiv").append(frag);
Prestaul
  • 83,552
  • 10
  • 84
  • 84
  • 1
    This worked for me, but I had to use append(), not appendChild(). Typo, or has the method name changed? – Glenn Barnett Dec 09 '09 at 21:59
  • I'm not sure how that might have slipped by, but I don't think that it is a renamed method. I'll update my post. – Prestaul Dec 11 '09 at 00:26
  • 1
    appendChild() is the w3c DOM method that does the same thing as append() in jQuery (approx.) – xj9 Aug 25 '10 at 02:11
  • `appendChild` only works for appending nodes; not an HTML string or an Object. – rxgx Jan 28 '11 at 02:20
  • 1
    Wouldn't `$("#mydiv").append(""+tableInnerHtml+"
    ");` do the same? What is the advantage of using `document.createElement()`?
    – Lèse majesté Jul 29 '12 at 22:07
9

What are you attempting to avoid? "A bad feeling" is incredibly vague. If you have heard "the DOM is slow" and decided to "avoid the DOM", then this is impossible. Every method of inserting code into a page, including innerHTML, will result in DOM objects being created. The DOM is the representation of the document in your browser's memory. You want DOM objects to be created.

The reason why people say "the DOM is slow" is because creating elements with document.createElement(), which is the official DOM interface for creating elements, is slower than using the non-standard innerHTML property in some browsers. This doesn't mean that creating DOM objects is bad, it is necessary to create DOM objects, otherwise your code wouldn't do anything at all.

Jim
  • 72,985
  • 14
  • 101
  • 108
2

The answer about using a DOM fragment is on the right track. If you have a bunch of html objects that you are constant inserting into the DOM then you will see some speed improvements using the fragment. This post by John Resig explains it pretty well: http://ejohn.org/blog/dom-documentfragments/

Sugendran
  • 2,099
  • 1
  • 14
  • 15
  • He didn't mention that he wants to put a fragment to more than one elements. His question indicates that he wants to put one html frag into one element. Besides, `document fragment` is created inside jQuery implicitly. – gblazex Dec 12 '10 at 10:10
2

The fastest way to append items

The fastest way to append to the DOM tree is to buffer all of your append in to a single DOM fragment, then append the dom fragment to the dom.

This is the method I use in my game engine.

//Returns a new Buffer object
function Buffer() {

    //the framgment
    var domFragment = document.createDocumentFragment();

    //Adds a node to the dom fragment
    function add(node) {
        domFragment.appendChild(node);
    }

    //Flushes the buffer to a node
    function flush(targetNode) {

        //if the target node is not given then use the body
        var targetNode = targetNode || document.body;

        //append the domFragment to the target
        targetNode.appendChild(domFragment);

    }

    //return the buffer
    return {
        "add": add,
        "flush": flush
    }
}


//to make a buffer do this
var buffer = Buffer();

//to add elements to the buffer do the following
buffer.add(someNode1);

//continue to add elements to the buffer
buffer.add(someNode2);
buffer.add(someNode3);
buffer.add(someNode4);
buffer.add(someN...);

//when you are done adding nodes flush the nodes to the containing div in the dom
buffer.flush(myContainerNode);

Using this object i am able to render ~1000 items to the screen ~40 times a second in firefox 4.

Here's a use case.

Robert Hurst
  • 8,902
  • 5
  • 42
  • 66
  • I wrote that code thanks! The question is "what is the fastest way to append to the dom" The guy is inserting a table. It doesn't matter if its a table or a div. Obviously you didn't read my answer very well. And saying that perceptually insertion is faster than buffering and appending is still flat out wrong. If you can't understand the relevance that's to bad for you. – Robert Hurst Jun 10 '11 at 23:49
  • It doesn't suprise me if you "wrote" it, there's nothing magical about it, I didn't even say it's wrong in itself, the thing is it's still not related to the question. And still doesn't give you the right to call anyone else's answer, who cares to read the question, to be dishonest. You're dishonest to common sense. – gblazex Jun 11 '11 at 09:36
  • What does that even mean dishonest to common sense? The guy wanted to insert a number of table related nodes. A DOM fragment will do this. You just seem like you have a superiority complex. – Robert Hurst Nov 29 '11 at 05:05
1

For starters, write a script that times how long it takes to do it 100 or 1,000 times with each method.

To make sure the repeats aren't somehow optimized away--I'm no expert on JavaScript engines--vary the html you're inserting every time, say by putting '0001' then '0002' then '0003' in a certain cell of the table.

Kev
  • 15,899
  • 15
  • 79
  • 112
0

I create a giant string with and then append this string with jquery. Works good and fast, for me.

-1

You mention being interested in alternatives. If you look at the listing of DOM-related jQuery plugins you'll find several that are dedicated to programatically generating DOM trees. See for instance SuperFlyDom or DOM Elements Creator; but there are others.

Avdi
  • 18,340
  • 6
  • 53
  • 62