<div>
<div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div>
<h2 id="one">One (has no ancestor class)</h2>
</div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div>
</div>
/*your preparation JavaScript code goes here
one = document.getElementById('one');
To execute async code during the script preparation, wrap it as function globalMeasureThatScriptPrepareFunction, example:*/
async function globalMeasureThatScriptPrepareFunction() {
// This function is optional, feel free to remove it.
// await someThing();
}
one.closest('.apple, .banana, .coconut, .dragonfruit, .eggplant, .fig, .grape');
['.apple', '.banana', '.coconut', '.dragonfruit', '.eggplant', '.fig', '.grape'].some((className) => one.closest(className));
one.closest('.apple, .banana, .coconut, .dragonfruit, .eggplant, .fig, .grape, .extra1, .extra2, .extra3');
['.apple', '.banana', '.coconut', '.dragonfruit', '.eggplant', '.fig', '.grape', '.extra1', '.extra2', '.extra3'].some((className) => one.closest(className));
--enable-precise-memory-info
flag.
Test case name | Result |
---|---|
Single .closest() with multiple classes, no match | |
Loop through classes, no match | |
Single .closest() with multiple classes, no match (plus 3 classes) | |
Loop through classes, no match (plus 3 classes) |
Test name | Executions per second |
---|---|
Single .closest() with multiple classes, no match | 843764.2 Ops/sec |
Loop through classes, no match | 342196.2 Ops/sec |
Single .closest() with multiple classes, no match (plus 3 classes) | 657774.8 Ops/sec |
Loop through classes, no match (plus 3 classes) | 238290.2 Ops/sec |
The benchmark provided tests the performance of different methods for traversing the DOM using the .closest()
JavaScript function and a loop with Array.prototype.some()
. It compares four different approaches to find the closest ancestor element that matches one or several specified classes.
Single .closest()
with multiple classes, no match:
one.closest('.apple, .banana, .coconut, .dragonfruit, .eggplant, .fig, .grape');
Loop through classes, no match:
['.apple', '.banana', '.coconut', '.dragonfruit', '.eggplant', '.fig', '.grape'].some((className) => one.closest(className));
Single .closest()
with multiple classes, no match (plus 3 classes):
one.closest('.apple, .banana, .coconut, .dragonfruit, .eggplant, .fig, .grape, .extra1, .extra2, .extra3');
Loop through classes, no match (plus 3 classes):
['.apple', '.banana', '.coconut', '.dragonfruit', '.eggplant', '.fig', '.grape', '.extra1', '.extra2', '.extra3'].some((className) => one.closest(className));
.closest()
MethodPros:
Cons:
Array.prototype.some()
Pros:
Cons:
Execution Performance: In the benchmarks, it becomes evident that the single .closest()
method, despite having multiple selectors, generally outperformed the looping method significantly. This points towards the efficiency of native methods over looping constructs.
Browser Variability: The performance can be affected by the browser's JavaScript engine optimizations. The results provided are from Firefox 135, so the outcomes may differ across other browsers and versions.
Use of a library: Libraries such as jQuery can abstract some of this DOM manipulation, providing a simpler API for selecting elements, but may introduce additional overhead when the library is loaded.
$('#one').closest('.apple, .banana, .coconut');
CSS Selector matches()
: Another alternative would be to combine JavaScript with the matches()
method to verify each ancestor more directly, though this may resemble the looping construct:
let element = one;
while (element && !element.matches('.apple, .banana, .coconut')) {
element = element.parentElement;
}
These approaches illustrate how to navigate from specificity vs performance trade-offs, and they can offer a richer understanding of DOM traversal techniques in modern JavaScript. Each method has distinct advantages that may be applicable depending on the use case, how many elements are being evaluated, and performance considerations specific to the environment in which the code is running.