innerHTML vs removeChild (v199)

Revision 199 of this benchmark created by blackmambahk on


Description

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 HTML

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

Setup

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();

Teardown


    document.getElementById('container').removeChild(box);
  

Test runner

Ready to run.

Testing in
TestOps/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);
ready
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);
 
ready
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;
ready
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);
}
ready
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);
}
ready
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>';
}
ready
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);
}
ready
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);
 
ready
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;

 
ready
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);
ready
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);
ready
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);
ready
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);
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.