jsPerf.app is an online JavaScript performance benchmark test runner & jsperf.com mirror. It is a complete rewrite in homage to the once excellent jsperf.com now with hopefully a more modern & maintainable codebase.
jsperf.com URLs are mirrored at the same path, e.g:
https://jsperf.com/negative-modulo/2
Can be accessed at:
https://jsperf.app/negative-modulo/2
<p id="foo">Foo</p>
<p id="bar">Bar</p>
<p id="baz">Baz</p>
<script>
function DOMHashMap(){
this._tagMap = {};
this._classMap = {};
this._idMap = {};
/*insert element into class and tag hash lists*/
this.put = function(e){
/*class*/
if(e.className){
var classes = e.className.split(" ");
for(var i = 0; i < classes.length; i++){
if(typeof(this._classMap[classes[i]]) == 'undefined'){
this._classMap[classes[i]] = [];
}
this._classMap[classes[i]].push(e);
}
}
/*id*/
if(e.id){
this._idMap[e.id] = e;
}
/*tag*/
if(typeof(this._tagMap[e.tagName]) == 'undefined'){
this._tagMap[e.tagName] = [];
}
this._tagMap[e.tagName].push(e);
};
/*return a hash list*/
this.getClass = function(k){
return this._classMap[k];
};
/*return a hash list*/
this.getId = function(k){
return this._idMap[k];
};
/*return a hash list*/
this.getTag = function(k){
return this._tagMap[k.toUpperCase()];
};
/*remove a document element from the hash map
parameter e is a document element object*/
this.remove = function(e){
/*delete from class hash list*/
if(e.className){
var classes = e.className.split(" ");
for(var i = 0; i < classes.length; i++){
if(typeof(this._classMap[classes[i]]) != 'undefined'){
for(var j = 0; j <this._classMap[classes[i]].length; j++){
if(e === this._classMap[classes[i]][j]) this._classMap[classes[i]].splice(j,1);
}
}
}
}
/*delete from id hash list*/
if(e.id){
var tag = e.id;
if(typeof(this._idMap[tag]) != 'undefined'){
for(var i = 0; i <this._idMap[tag].length; i++){
if(e === this._idMap[tag][i]) this._idMap[tag].splice(i,1);
}
}
}
/*delete from tag hash list*/
var tag = e.tagName;
if(typeof(this._tagMap[tag]) != 'undefined'){
for(var i = 0; i <this._tagMap[tag].length; i++){
if(e === this._tagMap[tag][i]) this._tagMap[tag].splice(i,1);
}
}
};
}
/** updateChildHashMap : FUNCTION
*
* @param : root(HTML DOM node) node that's children are to be populated/deleted with/of DOMHashMaps
*
* @param : isAdd(boolean) whether to add or remove the sub children of root
*
* @return : childList(array) of children of root(including root)
*
* Walks through the subtree of @param root either initializing the DOMHashMaps of its children, or populating an array of the children to be removed from its ancestors -
* depending on @param isAdd
*
*/
function updateChildHashMap(root,isAdd){
root.exists = 1;
if(typeof(root.map) == 'undefined'){
root.map = new DOMHashMap();
}
/*basecase*/
if(typeof(root.children) == 'undefined') return new Array();
else if(root.children.length == 0){
var list = [];
list.push(root);
return list;
}
/*recursive step*/
else{
var childList = new Array();
for(var i = 0; i < root.children.length; i++){
var currentChildList = {};
currentChildList.list = updateChildHashMap(root.children[i],isAdd);
for(var j = 0; j < currentChildList.list.length; j++){
childList.push(currentChildList.list[j]);
if(isAdd) root.map.put(currentChildList.list[j]);
else root.map.remove(currentChildList.list[j]);
}
delete currentChildList.list;
currentChildList = null;
}
childList.push(root);
return childList;
}
}
/** updateAncestorHashMap : FUNCTION
*
* @param : target(HTML DOM node) to add/remove a list of newly appended/removed children
*
* @param : childList(array) of children to add/remove to/from @param target
*
* @param : isAdd(boolean) whether to add or remove the childList
*
* @return : None
*
* Walks up the tree from the newly appended/removed node to remove or delete the children
*
*/
function updateAncestorHashMap(target,childList,isAdd){
if(target.parentNode){
for(var i = 0; i < childList.length; i++){
if(isAdd) target.parentNode.map.put(childList[i]);
else target.parentNode.map.remove(childList[i]);
}
if(target.parentNode.tagName != "BODY") updateAncestorHashMap(target.parentNode,childList,isAdd);
else return;
}
else return;
}
/** updateHashMap : FUNCTION
*
* @param : target(HTML DOM node) to add/remove a list of newly appended/removed children
*
* @param : isAdd(boolean) whether to add or remove the childList
*
* @return : None
*
* update the DOMHashMaps of all involved HTML Nodes
*
*/
function updateHashMap(target,isAdd){
var childList = {};
childList.list = updateChildHashMap(target,isAdd);
updateAncestorHashMap(target,childList.list,isAdd);
delete childList.list;
childList = null;
}
/** initialize : FUNCTION
*
* @param : None
*
* @return : None
*
* Initailize DOMHashMaps for all current HTML DOM nodes in the current document.
* Replace native appendChild and removeChild with new versions that update the DOMHashMaps.
* Adds fastGetElement[s]By[Tag|Class|Id) to all the HTML DOM Element prototypes
*
*/
function initialize(){
/*indentify browser*/
var browser = {
chrome : false,
minefield : false,
firefox : false,
ie : false,
};
if(navigator.userAgent.match("Chrome")) browser.chrome = true;
else if(navigator.userAgent.match("Minefield")) browser.minefield = true;
else if(navigator.userAgent.match("Mozilla")) browser.firefox = true;
/*create new DOM manipulation functions to replace existing*/
var getParent = function(e){
if(e.parentNode){
if(e.parentNode.map) return e;
else return getParent(e.parentNode);
}
else return e;
}
var appendChildWithEvent = function(e){
/*if e exists in the document, remove it first from the DOMHashMaps*/
if(e.exists) updateHashMap(e,false);
this.nativeAppendChild(e);
e = getParent(e);
updateHashMap(e,true);
};
var removeChildWithEvent = function(e){
parent = getParent(e);
updateHashMap(parent,false);
this.nativeRemoveChild(e);
};
/*add DOM manipulation functions to the document*/
document.haliaGetElementsByTagName = function(tag){return this.body.map.getTag(tag);};
document.haliaGetElementsByClassName = function(tag){return this.body.map.getClass(tag);};
document.haliaGetElementById = function(tag){return this.body.map.getId(tag);};
/*browser specific application of new DOM manipulation functions*/
if(browser.chrome){
Element.prototype.nativeAppendChild = Element.prototype.appendChild;
Element.prototype.appendChild = appendChildWithEvent;
Element.prototype.nativeRemoveChild = Element.prototype.removeChild;
Element.prototype.removeChild = removeChildWithEvent;
Element.prototype.haliaGetElementsByTagName = function(tag){return this.map.getTag(tag);};
Element.prototype.haliaGetElementsByClassName = function(tag){return this.map.getClass(tag);};
Element.prototype.haliaGetElementById = function(tag){return this.map.getId(tag);};
}
else if(browser.minefield){
var elements = ["HTMLHtmlElement","HTMLHeadElement","HTMLLinkElement","HTMLTitleElement","HTMLMetaElement",
"HTMLBaseElement","HTMLIsIndexElement","HTMLStyleElement","HTMLBodyElement","HTMLFormElement",
"HTMLSelectElement","HTMLOptGroupElement","HTMLOptionElement","HTMLInputElement","HTMLTextAreaElement",
"HTMLButtonElement","HTMLLabelElement","HTMLFieldSetElement","HTMLLegendElement","HTMLUListElement",
"HTMLOListElement","HTMLDListElement","HTMLDirectoryElement","HTMLMenuElement","HTMLLIElement",
"HTMLDivElement","HTMLParagraphElement","HTMLHeadingElement","HTMLQuoteElement","HTMLPreElement",
"HTMLFontElement","HTMLHRElement","HTMLAnchorElement",
"HTMLImageElement","HTMLObjectElement","HTMLParamElement","HTMLAppletElement","HTMLMapElement",
"HTMLAreaElement","HTMLScriptElement","HTMLTableElement","HTMLTableCaptionElement","HTMLTableColElement",
"HTMLTableSectionElement","HTMLTableRowElement","HTMLTableCellElement","HTMLFrameSetElement","HTMLFrameElement",
"HTMLIFrameElement"];
for(var i = 0; i < elements.length; i++){
var e = eval(elements[i]);
e.prototype.nativeAppendChild = e.prototype.appendChild;
e.prototype.appendChild = appendChildWithEvent;
e.prototype.nativeRemoveChild = e.prototype.removeChild;
e.prototype.removeChild = removeChildWithEvent;
e.prototype.haliaGetElementsByTagName = function(tag){return this.map.getTag(tag);};
e.prototype.haliaGetElementsByClassName = function(tag){return this.map.getClass(tag);};
e.prototype.haliaGetElementById = function(tag){return this.map.getId(tag);};
}
}
else if(browser.firefox){
var elements = ["HTMLHtmlElement","HTMLHeadElement","HTMLLinkElement","HTMLTitleElement","HTMLMetaElement",
"HTMLBaseElement","HTMLIsIndexElement","HTMLStyleElement","HTMLBodyElement","HTMLFormElement",
"HTMLSelectElement","HTMLOptGroupElement","HTMLOptionElement","HTMLInputElement","HTMLTextAreaElement",
"HTMLButtonElement","HTMLLabelElement","HTMLFieldSetElement","HTMLLegendElement","HTMLUListElement",
"HTMLOListElement","HTMLDListElement","HTMLDirectoryElement","HTMLMenuElement","HTMLLIElement",
"HTMLDivElement","HTMLParagraphElement","HTMLHeadingElement","HTMLQuoteElement","HTMLPreElement",
"HTMLFontElement","HTMLHRElement","HTMLAnchorElement",
"HTMLImageElement","HTMLObjectElement","HTMLParamElement","HTMLAppletElement","HTMLMapElement",
"HTMLAreaElement","HTMLScriptElement","HTMLTableElement","HTMLTableCaptionElement","HTMLTableColElement",
"HTMLTableSectionElement","HTMLTableRowElement","HTMLTableCellElement","HTMLFrameSetElement","HTMLFrameElement",
"HTMLIFrameElement"];
for(var i = 0; i < elements.length; i++){
var e = eval(elements[i]);
e.prototype.nativeAppendChild = e.prototype.appendChild;
e.prototype.appendChild = appendChildWithEvent;
e.prototype.nativeRemoveChild = e.prototype.removeChild;
e.prototype.removeChild = removeChildWithEvent;
e.prototype.haliaGetElementsByTagName = function(tag){return this.map.getTag(tag);};
e.prototype.haliaGetElementsByClassName = function(tag){return this.map.getClass(tag);};
e.prototype.haliaGetElementById = function(tag){return this.map.getId(tag);};
}
}
/*initialize the DOMHashMaps for the elements in the current document*/
updateChildHashMap(document.body,true);
}
initialize();
</script>
Ready to run.
Test | Ops/sec | |
---|---|---|
getElementById |
| ready |
querySelector |
| ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.