Wednesday, April 1, 2009

TaskSpeed: DOM VS Libraries

I tried to create an essential library to perform a manual implementation of the TaskSpeed test suite and results surprised me.

All these web 2.0 libraries are extremely useful, cool, time-saving, whatever you want, but not a single one can compete with manual tasks implementation, specially when we are talking about the most common browser which at the same time is the slowest ever: Internet Explorer!


Final Results for an Dual Core under Windows XP SP3


FireFox 3.0.8
------------------------
library | ms
------------------------
DOM 383
plugd-a (Dojo) 734
Dojo 1.3.0 742
Dojo 1.2.3 1008
MooTools 1.2.1 1252
jQuery 1.3.2 1935
jQuery 1.2.6 3518


Safari 4 Beta (528.16)
------------------------
library | ms
------------------------
DOM 118
plugd-a (Dojo) 170
Dojo 1.3.0 186
Dojo 1.2.3 342
MooTools 1.2.1 347
jQuery 1.3.2 602
jQuery 1.2.6 1025


Opera 10.00 alpha
------------------------
library | ms
------------------------
DOM 111
Dojo 1.3.0 251
plugd-a (Dojo) 374
MooTools 1.2.1 688
Dojo 1.2.3 938
jQuery 1.3.2 1329
jQuery 1.2.6 2327


Internet Explorer 6
------------------------
library | ms
------------------------
DOM 3966
Dojo 1.2.3 22750
plugd-a (Dojo) 24189
Dojo 1.3.0 24249
jQuery 1.3.2 44314
MooTools 1.2.1 69346
jQuery 1.2.6 104407


Internet Explorer 7
------------------------
library | ms
------------------------
DOM 612
Dojo 1.2.3 3641
plugd-a (Dojo) 3748
Dojo 1.3.0 3861
jQuery 1.3.2 5031
MooTools 1.2.1 7658
jQuery 1.2.6 10468


Internet Explorer 8
------------------------
library | ms
------------------------
DOM 499
Dojo 1.3.0 2327
plugd-a (Dojo) 2455
Dojo 1.2.3 2922
jQuery 1.3.2 3170
MooTools 1.2.1 5876
jQuery 1.2.6 7049



The essential library


var $ = {
// essential stuff for TaskSpeed test by WebReflection
// Mit Style License
addEventListener:document.addEventListener?
function(name, callback, bool){
this.addEventListener(name, callback, bool);
}:
function(name, callback, bool){
this.attachEvent("on" + name, callback);
}
,
getSimple:function(selector){
for(var
split = selector.split("."),
result = [],
re = new RegExp("\\b" + split[1] + "\\b"),
list = this.getElementsByTagName(split[0] || "*"),
length = list.length,
i = 0,
j = 0,
node;
i < length; ++i
){
node = list[i];
if(re.test(node.className))
result[j++] = node;
};
return result;
},
indexOf:Array.prototype.indexOf || function(value, i){
for(var
length = this.length,
i = i < 0 ? i + length < 0 ? 0 : i + length : i || 0;
i < length && this[i] !== value;
++i
);
return length <= i ? -1 : i;
},
removeEventListener:document.removeEventListener?
function(name, callback, bool){
this.removeEventListener(name, callback, bool);
}:
function(name, callback, bool){
this.detachEvent("on" + name, callback);
}
,
slice:Array.prototype.slice
};


The test suite

// TaskSpeed, the DOM way by WebReflection
window.tests = {

"make": function(){
for(var
body = document.body,
ul = document.createElement("ul"),
li = document.createElement("li"),
i = 0,
fromcode;
i < 250; ++i
){
fromcode = ul.cloneNode(true);
fromcode.id = "setid" + i;
fromcode.className = "fromcode";
fromcode.appendChild(li.cloneNode(true)).appendChild(document.createTextNode("one"));
fromcode.appendChild(li.cloneNode(true)).appendChild(document.createTextNode("two"));
fromcode.appendChild(li.cloneNode(true)).appendChild(document.createTextNode("three"));
body.appendChild(fromcode);
};
return $.getSimple.call(body, "ul.fromcode").length;
},

"indexof" : function(){
for(var body = document.body, index = -1, i = 0; i < 20; ++i)
index = $.indexOf.call(body.getElementsByTagName("ul"), document.getElementById("setid150"));
return index;
},

"bind" : function(){
for(var callback = function(){}, li = document.body.getElementsByTagName("li"), length = li.length, i = 0, total = 0, node; i < length; ++i){
node = li[i];
if(node.parentNode.nodeName == "UL"){
++total;
$.addEventListener.call(node, "click", callback, false);
};
};
return total;
},

"attr" : function(){
for(var result = [], ul = document.body.getElementsByTagName("ul"), length = ul.length, i = 0; i < length; ++i)
result[i] = ul[i].id;
return result.length;
},

"bindattr" : function(){
for(var callback = function(){}, li = document.body.getElementsByTagName("li"), length = li.length, i = 0, total = 0, node; i < length; ++i){
node = li[i];
if(node.parentNode.nodeName == "UL"){
++total;
$.addEventListener.call(node, "mouseover", callback, false);
node.setAttribute("rel", "touched");
$.removeEventListener.call(node, "mouseover", callback, false);
};
};
return total;
},

"table": function(){
for(var
body = document.body,
table = document.createElement("table").appendChild(document.createElement("tbody")).parentNode,
tr = document.createElement("tr"),
td = document.createElement("td"),
length = 40,
i = 0,
madetable,
cell;
i < length; ++i
){
madetable = table.cloneNode(true);
madetable.className = "madetable";
cell = body.appendChild(madetable).firstChild.appendChild(tr.cloneNode(true)).appendChild(td.cloneNode(true));
cell.appendChild(document.createTextNode("first"));
cell.parentNode.insertBefore(td.cloneNode(true), cell);
};
tr = body.getElementsByTagName("tr");
length = tr.length;
i = 0;
for(var total = 0; i < length; ++i)
total += tr[i].getElementsByTagName("td").length;
return total;
},

"addanchor" : function(){
var a = document.createElement("a");
a.setAttribute("href", "http://example.com");
a.appendChild(document.createTextNode("link"));
for(var ul = $.getSimple.call(document.body, "ul.fromcode"), length = ul.length, i = 0, total = 0, childNodes, j, len, node; i < length; ++i){
childNodes = ul[i].childNodes;
j = 0;
len = childNodes.length;
while(j < len){
node = childNodes[j];
if(node.nodeName === "LI"){
++total;
node.appendChild(a.cloneNode(true));
};
++j;
};
};
return total;
},

"append": function(){
for(var div = document.createElement("div"), body = document.body, i = 0, node; i < 500; ++i){
node = div.cloneNode(true);
node.setAttribute("rel", "foo2");
body.appendChild(node);
};
for(var div = body.getElementsByTagName("div"), length = div.length, i = 0, total = 0; i < length; ++i)
total += div[i].getAttribute("rel") === "foo2";
return total;
},

"addclass-odd" : function(){
for(var div = document.body.getElementsByTagName("div"), length = div.length, i = 0, total = 0; i < length; ++i)
total += i % 2 ? !!(div[i].className += " added odd") : !(div[i].className += " added");
return total;
},

"style" : function(){
for(var div = $.getSimple.call(document.body, "div.added"), length = div.length, i = 0, style; i < length; ++i){
style = div[i].style;
style.backgroundColor = "#ededed";
style.color = "#fff";
};
return length;
},

"removeclass" : function(){
for(var re = /\s*\badded\b/g, div = $.getSimple.call(document.body, "div.added"), length = div.length, i = 0, node; i < length; ++i){
node = div[i];
node.className = node.className.replace(re, "");
};
return length;
},

"sethtml": function(){
for(var div = document.body.getElementsByTagName("div"), length = div.length, i = 0; i < length; ++i)
div.innerHTML = "<p>new content</p>";
return div.length;
},

"insertbefore" : function(){
for(var p = document.createElement("p"), ul = $.getSimple.call(document.body, "ul.fromcode"), length = ul.length, i = 0, total = 0; i < length; ++i){
for(var a = ul[i].getElementsByTagName("a"), len = a.length, j = 0, node; j < len; ++j){
++total;
node = a[j];
node.parentNode.insertBefore(p.cloneNode(true).appendChild(document.createTextNode("A Link")).parentNode, node);
};
};
return total;
},

"insertafter" : function(){
for(var p = document.createElement("p"), ul = $.getSimple.call(document.body, "ul.fromcode"), length = ul.length, i = 0, total = 0; i < length; ++i){
for(var a = ul[i].getElementsByTagName("a"), len = a.length, j = 0, node; j < len; ++j){
++total;
node = a[j];
node.parentNode.appendChild(p.cloneNode(true).appendChild(document.createTextNode("After Link")).parentNode);
};
};
return total;
},

"destroy": function(){
var result = $.getSimple.call(document.body, "ul.fromcode"),
length = result.length,
i = 0,
node;
while(i < length){
node = result[i++];
node.parentNode.removeChild(node);
};
return length;
},

"finale": function(){
var body = document.body;
while(body.firstChild)
body.removeChild(body.firstChild);
return body.getElementsByTagName("*").length;
}

};


Conclusion

I do not want to spend a word about these results, but I guess we have to think about them.

No comments:

Post a Comment