Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is "element.innerHTML+=" bad code?

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?

like image 231
ajax333221 Avatar asked Jul 17 '12 02:07

ajax333221


People also ask

Why is innerHTML bad practice?

'innerHTML' Presents a Security Risk The use of innerHTML creates a potential security risk for your website. Malicious users can use cross-site scripting (XSS) to add malicious client-side scripts that steal private user information stored in session cookies.

What is the disadvantage of innerHTML?

There is no append support without reparsing the whole innerHTML. This makes changing innerHTML directly very slow. innerHTML does not provide validation and therefore we can potentially insert valid and broken HTML in the document and break it.

What happens when you set the innerHTML of an element?

A string containing the HTML serialization of the element's descendants. Setting the value of innerHTML removes all of the element's descendants and replaces them with nodes constructed by parsing the HTML given in the string htmlString.

Why should you create DOM elements instead of using innerHTML?

#1) createElement is more performant Therefore, it is less efficient than creating a new element and appending to the div. In other words, creating a new element and appending it to the DOM tree provides better performance than the innerHTML .


2 Answers

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:

var newElement = document.createElement('div'); newElement.innerHTML = '<div>Hello World!</div>'; elm.appendChild(newElement);​​​​​​​​​​​​​​​​ 

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.

like image 154
Mike Christensen Avatar answered Oct 26 '22 23:10

Mike Christensen


Yes, elm.innerHTML += str; is a very bad idea.
Use elm.insertAdjacentHTML( 'beforeend', str ) as the perfect alternative.

The typical "browser has to rebuild DOM" answer really doesn't do the question justice:

  1. 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.

  2. Then you have a long string, which you append to. This step is ok.

  3. Third, when you set innerHTML, browser has to remove all the elements, properties, and nodes it just went through.

  4. 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.

  5. 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.

  6. 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 belong 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 keep reference to 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 on all browsers.

Don't ever write elm.innerHTML+= again.

like image 44
Sheepy Avatar answered Oct 26 '22 23:10

Sheepy