innerHTML vs removeChild

JavaScript performance comparison

Revision 199 of this test case created by blackmambahk

Info

An attempt at a realistic simulation.

Assume a set of 400 nodes and there is some change requiring 150 nodes to be replaced.

What is the most efficient way to do that?

InnerHTML test does a complete replacement of all 400 nodes because thats all innerHTML can do, whilst the other tests only change the 150 nodes, the Control test does the same thing on all 400 nodes using remove/appendChild to help better understand the relative performance of innerHTML vs node manipulation. InnerHTML + Clone look to a faster way to replace all nodes.

Conclusion is that although innerHTML is more performant than node manipulation when replacing all child nodes, node manipulation often allows you to do less work and is therefore faster in removing a subset of nodes, noting that even so bulk inserting nodes via insertAdjacentHTML is faster than appending nodes.

The Update tests look to simply update the content of a node instead of removing and then appending it, thereby saving creating new dom nodes. Both test are slower!

Preparation code

<div id="container"></div>
<style type="text/css">
    #box, #box * {
        font-size: 0;
    }
    #box * {
        display: inline-block;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: 0;
        background-color: blue;
    }
</style>
<script>
Benchmark.prototype.setup = function() {
    var box = document.createElement('div');
    box.id = 'box';
    document.getElementById('container').appendChild(box);
    function refill(){
      var box = document.getElementById('box');;
      var html='';
      var n = '<div><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span></div>';
      for(i=0;i<400;i++)html+=n;
      box.innerHTML=html;
    }
    refill();
};

Benchmark.prototype.teardown = function() {
    document.getElementById('container').removeChild(box);
};
</script>

Preparation code output

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
RemoveChild
var box = document.getElementById('box');;
for(i=0;i<150;i++)box.removeChild(box.childNodes[299-i]);
var html='';
var n = '<div><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span></div>';
for(i=0;i<150;i++)html+=n;
box.insertAdjacentHTML('beforeEnd',html);
pending…
Range
var box = document.getElementById('box');;
var range = document.createRange();
range.setStart(box.childNodes[150],0);
range.setEnd(box.childNodes[299],0);
range.deleteContents();
var html='';
var n = '<div><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span></div>';
for(i=0;i<150;i++)html+=n;
box.insertAdjacentHTML('beforeEnd',html);
 
pending…
InnerHTML
var box = document.getElementById('box');;
var html='';
var n = '<div><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span></div>';
for(i=0;i<400;i++)html+=n;
box.innerHTML=html;
pending…
Append
var box = document.getElementById('box');;
for(i=0;i<150;i++)box.removeChild(box.childNodes[299-i]);
for(i=0;i<150;i++){
d = document.createElement('div');
d.innerHTML='<span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span>';
box.appendChild(d);
}
pending…
Control
var box = document.getElementById('box');;
for(i=0;i<400;i++)box.removeChild(box.childNodes[399-i]);
for(i=0;i<400;i++){
d = document.createElement('div');
d.innerHTML='<span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span>';
box.appendChild(d);
}
pending…
Update
var box = document.getElementById('box');;
for(i=0;i<150;i++){
 box.childNodes[299-i].innerHTML='<span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span>';
}
pending…
Update outside dom
var box = document.getElementById('box');
for(i=0;i<150;i++){
var d = box.removeChild(box.childNodes[299-i]);
d.innerHTML='<span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span>';
box.appendChild(d);
}
pending…
InnerHTML+Clone
var box = document.getElementById('box');;

var newBox = box.cloneNode(false);

var html='';
var n = '<div><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span></div>';
for(i=0;i<400;i++)html+=n;

newBox.innerHTML=html;

box.parentNode.replaceChild(newBox, box);
 
pending…
InnerText/InnerHTML
var box = document.getElementById('box');;

var html='';
var n = '<div><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span></div>';
for(i=0;i<400;i++)html+=n;

box.innerText='';
box.innerHTML=html;

 
pending…
Fragment
var box = document.getElementById('box');;
for(i=0;i<150;i++)box.removeChild(box.childNodes[299-i]);
var frag = document.createDocumentFragment();
for(i=0;i<150;i++){
d = document.createElement('div');
for(var j=0;j<10;j++){
  s = document.createElement('span');
  s.textContent='a';
  d.appendChild(s);
}
frag.appendChild(d);
}

box.appendChild(frag);
pending…
Fragment Partial
var box = document.getElementById('box');;
for(i=0;i<150;i++)box.removeChild(box.childNodes[299-i]);
var frag = document.createDocumentFragment();
for(i=0;i<150;i++){
d = document.createElement('div');
var n = '<span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span>';
d.innerHTML=d;
frag.appendChild(d);
}

box.appendChild(frag);
pending…
Frag Partial 400
var box = document.getElementById('box');;
for(i=0;i<400;i++)box.removeChild(box.childNodes[399-i]);
var frag = document.createDocumentFragment();
for(i=0;i<400;i++){
d = document.createElement('div');
var n = '<span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span>';
d.innerHTML=d;
frag.appendChild(d);
}

box.appendChild(frag);
pending…
Frag 400 InnerText
var box = document.getElementById('box');;
box.innerText='';
var frag = document.createDocumentFragment();
for(i=0;i<400;i++){
d = document.createElement('div');
var n = '<span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span><span>a</span>';
d.innerHTML=d;
frag.appendChild(d);
}

box.appendChild(frag);
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:

0 comments

Add a comment