2

I want to get all the elements that are having an ID and want to store that id value in an array and I am using the following method:

var allTheElementsHavingID = document.querySelectorAll('[id]');
var allTheID = [];
for(i=0;i<allTheElementsHavingID.length;i++)
{
  allTheID.push(allTheElementsHavingID[i].id);
}

But the problem here is that I am having around 15000 elements with an ID. and when I run the code in console it freezes the browser. so I want the alternative of the for loop here so as to store all the ID's Is there any other method?? that will prove more efficient

Karan Parikh
  • 311
  • 3
  • 18

4 Answers4

1

Try this. it will change the loop to perform asynchronously so it can take as long as it needs to process the elements and will not crash the browser.

const els = document.querySelectorAll('[id]')

function asyncLoop(els, callback) {
  let ii = 0
  const ret = []
  const length = els.length
  
  function iter() {
    const id = els[ii].id
    const link = document.querySelector(`a[href*=${id}]`)
    if (!link) {
      ret.push(els[ii].id)
    }
    if (++ii < length) {
      return setTimeout(iter, 0)
    }
    callback(ret)
  }
  iter()
}

asyncLoop(els, function(missingIds){
  console.log(missingIds)
})
<a id="one" href="#one">one</a>
<a id="two" href="#two">two</a>
<a id="fail" href="#three">three</a>

I'm not sure that getting and iterating a list with 15,000 elements is a good idea. You could evaluate the 'hashchange' to see if there is a matching element when the link is clicked. It would give you the chance to handle any errors.

returning !!element will prevent the action if there is no matching element

window.addEventListener('hashchange', function(e) {
  var element = document.querySelector(location.hash)
  console.log(element)
  return !!element
})
<a id="one" href="#one">one</a>
<a id="two" href="#two">two</a>
<a id="fail" href="#three">three</a>
synthet1c
  • 6,152
  • 2
  • 24
  • 39
  • Thanks the solution is good, Is there a way by which I can know if there is matching element without clicking the link??? – Karan Parikh Oct 15 '16 at 15:13
  • Not with this solution. why do you have such a large list and so many id's on the page? and are there less links with hrefs than id's? – synthet1c Oct 15 '16 at 15:15
  • the requirement is to publish a book in html format and the book's page no. are 1237 each page consist of something that has to be linked. – Karan Parikh Oct 15 '16 at 15:18
  • I think there is some confusion, – Karan Parikh Oct 15 '16 at 15:19
  • So this is a one time script in your compilation for a static asset that can be distributed, or you need to do this each time a webpage is open? – synthet1c Oct 15 '16 at 15:20
  • Yes synthet1c its one time script compilation at my end only, not everytime when webpage is open. But I have other books also which are having same number of links therefore I turned to develop a common solution. – Karan Parikh Oct 15 '16 at 15:23
  • @KaranParikh edited the answer. That script will not care how many elements you give it or how long it takes, and it shouldn't prevent you from interacting with the page. – synthet1c Oct 15 '16 at 15:41
1

The basic problem is that looping over so many items is always going to take some time. But maybe using a built-in function like .map() will be faster than your own loop.

var allTheID = [].map.call(allTheElementsHavingID, e => e.id);

But apparently I'm wrong.

JQuery map vs Javascript map vs For-loop

Community
  • 1
  • 1
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • I thought native loops were faster than the Array methods. – synthet1c Oct 15 '16 at 15:16
  • You're right, I found some other questions that address that. – Barmar Oct 15 '16 at 15:18
  • I think you should still use the Array methods as they are easier to understand and it gives the browser vendors the ability to optimize their code behind the scenes. 15,000 iterations is a fair bit though. – synthet1c Oct 15 '16 at 15:22
  • For small arrays that's probably right. But if the loop is a performance bottleneck, using a slower method will just make things even worse. – Barmar Oct 15 '16 at 15:24
0

Try map:

The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.

const allTheElementsHavingID = document.querySelectorAll('[id]');
const allTheID = [...allTheElementsHavingID].map(element => element.id);
console.log(allTheID);
<div id="one">a</div>
<div id="two">b</div>
<div id="three">c</div>
<div id="four">d</div>
<div id="five">e</div>

If you are using TypeScript and face this error:

Type 'IterableIterator' is not an array type or a string type. Use compiler option '--downlevelIteration' to allow iterating of iterators.

Instead of

[...allTheElementsHavingID].map(element => element.id)]

you can rely on Array.from()

Array.from(allTheElementsHavingID, element => element.id)

More on downlevelIteration

aloisdg
  • 22,270
  • 6
  • 85
  • 105
-1

You could give them all the elements same class, then get the IDs of all the elements with the same class. Here is the jsfiddle https://jsfiddle.net/qdk9d55w/4/

 var elementIds = [];
 var elements = document.getElementsByClassName("example");
 for (var i = 0, len = elements.length; i < len; i++) {
    if (elements[i].id != '') {
        elementIds.push(elements[i].id);
    }
 }
 alert(elementIds);
Alex Rindone
  • 296
  • 2
  • 9
  • No Alex they are not same. – Karan Parikh Oct 15 '16 at 15:03
  • https://jsfiddle.net/qdk9d55w/ just give all of those elements the same class, regardless if the elements are different. – Alex Rindone Oct 15 '16 at 15:05
  • Thank you Alex but even if I add class name to all the elements the problem still exists because document.getElementsByClassName will return the elements with same class name not their "IDs" – Karan Parikh Oct 15 '16 at 15:15
  • Did you look at the js fiddle that I made? That is not true. I updated it. – Alex Rindone Oct 15 '16 at 15:15
  • I'm doing exactly what you are asking with this, grabbing all the elements you need, getting their ids, and putting them into an array. – Alex Rindone Oct 15 '16 at 15:24
  • I appreciate your time and efforts but, Alex the main concern was I don't want to insert the id's of the elements into the array through the iterations of for loop because the number of id's span upto 15000 – Karan Parikh Oct 15 '16 at 17:30
  • Oh, that makes sense then. I thought it was 15,000 elements on the entire page, not the amount of elements you needed. The question was confusing, getting that much data shouldn't be done the way you intend, just my opinion. – Alex Rindone Oct 15 '16 at 18:17
  • Sorry for confusing you and yeah your opinion is correct this is not the method that I should use. Open for suggestions – Karan Parikh Oct 15 '16 at 18:24