-
-
Save denilsonsa/6fdcc5a726220a85eb7c6a00e955d532 to your computer and use it in GitHub Desktop.
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"/> | |
<title>getElementsByClassName vs getElementById vs querySelector</title> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/1.0.0/benchmark.min.js"></script> | |
<script src="./suite.js"></script> | |
</head> | |
<body> | |
<h1>Open the console to view the results</h1> | |
<h2><code>cmd + alt + j</code> or <code>ctrl + alt + j</code></h2> | |
</body> | |
</html> |
"use strict"; | |
(function (factory) { | |
if (typeof Benchmark !== "undefined") { | |
factory(Benchmark); | |
} else { | |
factory(require("benchmark")); | |
} | |
})(function (Benchmark) { | |
var suite = new Benchmark.Suite; | |
Benchmark.prototype.setup = function () { | |
window.generated_divs = 5000; | |
let root = document.createElement("div"); | |
for(let i = 0; i < generated_divs; i++) { | |
let el = document.createElement("div"); | |
el.id = `foo${i}`; | |
el.className = `foo${i}`; | |
el.setAttribute(`foo${i}`, ''); | |
root.appendChild(el); | |
} | |
document.body.appendChild(root); | |
}; | |
Benchmark.prototype.teardown = function () { | |
document.body.removeChild(root); | |
root = null; | |
}; | |
suite.add("getElementById", function () { | |
// getElementById | |
let i = Math.floor(Math.random() * window.generated_divs); | |
let element = document.getElementById(`foo${i}`); | |
}); | |
suite.add("getElementsByClassName", function () { | |
// getElementsByClassName | |
let i = Math.floor(Math.random() * window.generated_divs); | |
let element = document.getElementsByClassName(`foo${i}`); | |
}); | |
suite.add("querySelector('#id')", function () { | |
// querySelector('#id') | |
let i = Math.floor(Math.random() * window.generated_divs); | |
let element = document.querySelector(`#foo${i}`); | |
}); | |
suite.add("querySelector('.class')", function () { | |
// querySelector('.class') | |
let i = Math.floor(Math.random() * window.generated_divs); | |
let element = document.querySelector(`.foo${i}`); | |
}); | |
suite.add("querySelector('[attr]]')", function () { | |
// querySelector('[attr]]') | |
let i = Math.floor(Math.random() * window.generated_divs); | |
let element = document.querySelector(`[foo${i}]`); | |
}); | |
suite.on("cycle", function (evt) { | |
console.log(" - " + evt.target); | |
}); | |
suite.on("complete", function (evt) { | |
console.log(new Array(30).join("-")); | |
var results = evt.currentTarget.sort(function (a, b) { | |
return b.hz - a.hz; | |
}); | |
results.forEach(function (item) { | |
console.log((idx + 1) + ". " + item); | |
}); | |
}); | |
console.log("getElementsByClassName vs getElementById vs querySelector"); | |
console.log(new Array(30).join("-")); | |
suite.run(); | |
}); |
The benchmark for getElementsByClassName
was actually incorrect, because the method only returns a HTMLCollection
, essentially a query term. You need to evaluate it before it finds elements.
So evaluating the result with [0]
shows the true performance:
full screenshot of upper part:
https://user-images.githubusercontent.com/33069673/132558324-14831ed0-12bc-43e3-96bf-c140a339fa7a.png
Here's my fork of the benchmark with the above fix:
http://jsbench.github.io/#a8f9a872efc2063a9365976fc26946e2
For that reason, in your version on jsbench getElementsByClassName
outperforms getElementsById
, which makes no sense, since the ids are indexed (in a hashmap = O(1)), while getElementsByClassName
needs to search the DOM tree.
https://user-images.githubusercontent.com/33069673/132554466-129ca976-48d2-4d63-9ffe-e1c446170b01.png
@denilsonsa otherwise great benchmark, thanks for sharing it (=
Great finding, @sschmidTU! Fully agree with your commments.
Benchmark available at: