I have been told not to append stuff using element.innerHTML += ...
like this:
var str = "<div>hello world</div>";
var elm = document.getElementById("targetID");
elm.innerHTML += str; //not a good idea?
What is wrong with it?, what other alternatives do I have?
Yes,
elm.innerHTML += str;
is a very bad idea.The typical "browser has to rebuild DOM" answer really doesn't do it justice:
First the browser need to go through each elements under elm, each of their properties, and all their texts & comments & process nodes, and escape them to build you a string.
Then you have a long string, which you append to. This step is ok.
Third, when you set innerHTML, browser has to remove all the elements, properties, and nodes it just went through.
Then it parse the string, build from all the elements, properties, and nodes it just destroyed, to create a new DOM fragment that is mostly identical.
Finally it attach the new nodes, and the browser has to layout the whole thing. This may be avoidable (see the alternative below), but even if the appended node(s) requires a layout, old nodes would have their layout properties cached instead of re-calculated from fresh.
But it's not done yet! The browser also have to recycle old nodes by scanning all javascript variables.
Problems:
Some properties may not be reflected by HTML, for example the current value of
<input>
will be lost and reset to the initial value in the HTML.If you have any event handlers on the old nodes, they will be destroyed and you have to reattach all of them.
If your js code is referencing any old nodes, they will not be destroyed but will instead be orphaned. They belongs to the document but is no longer in the DOM tree. When your code access them, nothing may happens or it may throws error.
Both problems means it is unfriendly with js plugins - the plugins may attach handlers or remember old nodes and cause memory leak.
If you get into the habit of doing DOM manipulation with innerHTML, you may accidentally change properties or do other things you didn't want to.
The more nodes you have, the more inefficient this is, the more battery juice for nothing.
In short, it is inefficient, it is error prone, it is simply lazy and uninformed.
The best alternative is
Element.insertAdjacentHTML
, that I haven't seen other answers mention:elm.insertAdjacentHTML( 'beforeend', str )
Almost same code, without innerHTML's problems. No rebuild, no handler lost, no input reset, less memory fragmentation, no bad habit, no manual element creations and assignments.
It allows you to inject html string into elements in one line, including properties, and even allows yow to inject composite and multiple elements. Its speed is optimised - in Mozilla's test it is 150 times faster.
In case someone tell you it is not cross browser, it is so useful that it is HTML5 standard and available in all browsers.
The alternative is
.createElement()
,.textContent
, and.appendChild()
. Appending with+=
is only an issue if you're dealing with a lot of data.Demo: http://jsfiddle.net/ThinkingStiff/v6WgG/
Script
HTML
If the user has older versions of IE (or maybe newer ones too, haven't tried), innerHTML on a
td
will cause issues. Table elements in IE are read-only, tsk tsk tsk.I just learned the hard way why innerHTML is bad, in this code below when you set innerHTML chrome loses the onclick event jsFiddle
Every time
innerHTML
is set, the HTML has to be parsed, a DOM constructed, and inserted into the document. This takes time.For example, if
elm.innerHTML
has thousands of divs, tables, lists, images, etc, then calling.innerHTML += ...
is going to cause the parser to re-parse all that stuff over again. This could also break references to already constructed DOM elements and cause other chaos. In reality, all you want to do is append a single new element to the end.It's better to just call
appendChild
:This way, the existing contents of
elm
are not parsed again.NOTE: It's possible that [some] browsers are smart enough to optimize the
+=
operator and not re-parse the existing contents. I have not researched this.Mike's answer is probably the better one, but another consideration is that you are dealing with strings. And string concatenation in JavaScript can be really slow especially in some older browsers. If you are just concatenating little fragments from HTML then it probably isn't noticeable, but if you have a major part of the page that you are appending something to repeatedly you very well could see a noticeable pause in the browser.