Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

fast interacting with large number of elements inside a container (DOM, javascript)

So I have a large number of divs (4000-5000) [each contains spans, anchors, images etc.] inside a container div and basically I am setting their display to none or block based on a condition. This does take some time.

In my search for something faster I came across this page https://developers.google.com/speed/articles/javascript-dom and the solution there is to remove the container div from the DOM and iterate the contained elements by getElementsByTagName.

/**
 * Remove an element and provide a function that inserts it into its original position
 * @param element {Element} The element to be temporarily removed
 * @return {Function} A function that inserts the element into its original position
 **/
function removeToInsertLater(element) {
  var parentNode = element.parentNode;
  var nextSibling = element.nextSibling;
  parentNode.removeChild(element);
  return function() {
    if (nextSibling) {
      parentNode.insertBefore(element, nextSibling);
    } else {
      parentNode.appendChild(element);
    }
  };
}


function updateAllAnchors(element, anchorClass) {
  var insertFunction = removeToInsertLater(element);
  var anchors = element.getElementsByTagName('a');
  for (var i = 0, length = anchors.length; i < length; i ++) {
    anchors[i].className = anchorClass;
  }
  insertFunction();
}

The problem is I cannot use the solution provided because I need to access the children elements by their IDs and I can't do that, since the elements are removed from the DOM. Is there any way to achieve this?

I also tried to remove the container div and append it to a documentfragment, but still I can't access the 5000 elements by their ID when they are in the documentfragment

Finally, I also tried this:

document.getElementById("CONTAINERDIV").style.display = "none";

//iterate through the 5000 children divs and change their classname

document.getElementById("CONTAINERDIV").style.display = "block";

because I was hoping that it would not trigger a reflow for each iteration, but this didn't seem to provide an improvement in the time required.

Does anyone have any thoughts on this?

like image 571
MirrorMirror Avatar asked Mar 05 '14 10:03

MirrorMirror


2 Answers

I will try to provide sources as requested.

First solution - best one
According to this site: JavaScript Grid with One Million Records
You can learn several important things:

  1. Large number of DOM nodes make rendering slow
  2. JavaScript arrays can handle large data sets
  3. Looping through large arrays is fast
  4. Sorting arrays by providing custom function to Array.sort() is fast
  5. eval() is slow, should not be used in large loops

So, I would recommend you to build an array to handle in a fast way your elements.

Second solution
Another solution taken from this site: Processing large amounts of data in JavaScript
would be to use a timeout (as strange as it sounds) to increase speed of handler.
The idea comes from Book: Secrets of the JavaScript Ninja

like image 64
Elfentech Avatar answered Oct 20 '22 00:10

Elfentech


If you want only to show/hide, without change anything in the div's DOM and you know all the IDs, I think, that the best (fastest) way to archive this would be to prepare <style /> element and append it to DOM. Style el should contain all the ID's and proper display. Iterate through IDs and add it to CSS string, then create <style /> element and append string to it. This should work for you.

like image 30
Krzysztof Romanowski Avatar answered Oct 19 '22 22:10

Krzysztof Romanowski