I assume that given the element where all its children are arranged sequentially in the document, the fastest way would be to perform a binary search by comparing the position of the document in the elements. However, as indicated in the conclusion, the hypothesis is rejected. The more elements you have, the greater the potential for productivity. For example, if you had 256 elements, then (optimally) you will need to check only 16 of them! For 65536, only 256! Performance increases to 2! See more numbers / statistics. Visit Wikipedia
(function(constructor){ 'use strict'; Object.defineProperty(constructor.prototype, 'parentIndex', { get: function() { var searchParent = this.parentElement; if (!searchParent) return -1; var searchArray = searchParent.children, thisOffset = this.offsetTop, stop = searchArray.length, p = 0, delta = 0; while (searchArray[p] !== this) { if (searchArray[p] > this) stop = p + 1, p -= delta; delta = (stop - p) >>> 1; p += delta; } return p; } }); })(window.Element || Node);
Then you use it, getting the parentIndex property of any element. For example, see the following demo.
(function(constructor){ 'use strict'; Object.defineProperty(constructor.prototype, 'parentIndex', { get: function() { var searchParent = this.parentNode; if (searchParent === null) return -1; var childElements = searchParent.children, lo = -1, mi, hi = childElements.length; while (1 + lo !== hi) { mi = (hi + lo) >> 1; if (!(this.compareDocumentPosition(childElements[mi]) & 0x2)) { hi = mi; continue; } lo = mi; } return childElements[hi] === this ? hi : -1; } }); })(window.Element || Node); output.textContent = document.body.parentIndex; output2.textContent = document.documentElement.parentIndex;
Body parentIndex is <b id="output"></b><br /> documentElements parentIndex is <b id="output2"></b>
Limitations
- This implementation of the solution will not work in IE8 and below.
Binary VS Linear Search On 200 thousand elements (some mobile browsers may crash, ATTENTION!):
- In this test, we will see how long it takes a linear search to find the middle element VS of a binary search. Why is the middle element? Since it is in the average location of all other locations, it therefore best represents all possible locations.
Binary search
(function(constructor){ 'use strict'; Object.defineProperty(constructor.prototype, 'parentIndexBinarySearch', { get: function() { var searchParent = this.parentNode; if (searchParent === null) return -1; var childElements = searchParent.children, lo = -1, mi, hi = childElements.length; while (1 + lo !== hi) { mi = (hi + lo) >> 1; if (!(this.compareDocumentPosition(childElements[mi]) & 0x2)) { hi = mi; continue; } lo = mi; } return childElements[hi] === this ? hi : -1; } }); })(window.Element || Node); test.innerHTML = '<div> </div> '.repeat(200e+3);
<output id=output> </output><br /> <div id=test style=visibility:hidden;white-space:pre></div>
Reverse ('lastIndexOf') linear search
(function(t){"use strict";var e=Array.prototype.lastIndexOf;Object.defineProperty(t.prototype,"parentIndexLinearSearch",{get:function(){return e.call(t,this)}})})(window.Element||Node); test.innerHTML = '<div> </div> '.repeat(200e+3);
<output id=output> </output><br /> <div id=test style=visibility:hidden;white-space:pre></div>
Forward ('indexOf') Linear Search
(function(t){"use strict";var e=Array.prototype.indexOf;Object.defineProperty(t.prototype,"parentIndexLinearSearch",{get:function(){return e.call(t,this)}})})(window.Element||Node); test.innerHTML = '<div> </div> '.repeat(200e+3);
<output id=output> </output><br /> <div id=test style=visibility:hidden;white-space:pre></div>
PreviousElementSibling Counter Search
Counts the number of PreviousElementSiblings to get parentIndex.
(function(constructor){ 'use strict'; Object.defineProperty(constructor.prototype, 'parentIndexSiblingSearch', { get: function() { var i = 0, cur = this; do { cur = cur.previousElementSibling; ++i; } while (cur !== null) return i;
<output id=output> </output><br /> <div id=test style=visibility:hidden;white-space:pre></div>
No search
To compare test results if the browser optimizes the search.
test.innerHTML = '<div> </div> '.repeat(200e+3);
<output id=output> </output><br /> <div id=test style=visibility:hidden></div>
Concussion
However, after viewing the results in Chrome, the results are the opposite of those expected. A linear search in the direction of βdumb forwardβ was surprisingly 187 ms, 3850% faster than binary search. Obviously, Chrome somehow outwitted console.assert
and optimized it, or (more optimistically) Chrome internally uses the numeric indexing system for the DOM, and this internal indexing system is revealed through optimizations applied to Array.prototype.indexOf
when used in HTMLCollection
object.
Jack Giffin Jul 02 '17 at 22:37 2017-07-02 22:37
source share