Daniel Moss
Daniel Moss

Reputation: 567

How can I re-write this function's comparisons and methods for better efficiency?

I have a function which runs about 30-40 times which helps me add a certain class to some layouts I have, if conditions are met. Unfortunately, it has proved itself a bit of a hog for the phone's CPU:

function addClassOnRequirement(target_div, target_div_unpacked, class_to_add, cols) {

    var len_list = $(target_div).length;

    // If layout has 2 columns
    if(cols === 2) {
        // If the layout has an odd number of items, add the said class.
        if (len_list % 2 === 1) {
            $(target_div_unpacked).addClass(class_to_add);
        }
        // If layout has 3 columns
    } else if(cols === 3) {
        // If the layout's number of items (3 on each row) has the number ~5 or so
        // add this class. If 2 rows, 3 items on first row, 2  items on 
        // second row exist, there
        // should be 6, so add this class to do some CSS jumble since 
        // they're 5.
        if (((len_list - 2) % 3) === 0) {
            $(target_div_unpacked).addClass(class_to_add);
        }
    }
}

target_div represents the selector for the <ul> of the layout.

target_div_unpacked represents the "pure" selector, without tags such as "ul"

class_to_add represents the name of the class to be added to target_div_unpacked

cols represents the number of cols I have to add.

All of which are hard-coded and are not generated from other functions, exactly like this:

addClassOnRequirement(".posts-layout3 li", ".posts-layout3", "col-3-last2-child-50-width", 3);

In a layout where it has to get the length of a big <ul> with lots of childs, such as:

<ul class="layout-to-test">
    <li></li>
    <li></li>
    <li></li>
    ..
    ..
    <li></li>
</ul>

The situation gets worse, because it has to iterate through it all, get the length, etc.

Here's what I followed for optimization:

Unfortunately, it seems that regardless of this, the function still clogs. How can I improve?

Upvotes: 1

Views: 58

Answers (2)

Alex Dacre
Alex Dacre

Reputation: 86

Is your problem that you want special rules depending on whether you have one too few list items in a multi-column list?

If so the most efficient way to solve this would be without javascript at all. You can solve this with css:

.three-col-list li {
  width: 32%;
  display: inline-block;
}

.three-col-list li:nth-child(3n + 2):nth-last-child(1) {
    background: gray;
}
<p>List 1</p>
<ul class="three-col-list">
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
</ul>

<p>List 2</p>
<ul class="three-col-list">
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
</ul>

<p>List 3</p>
<ul class="three-col-list">
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
</ul>

Upvotes: 1

cyr_x
cyr_x

Reputation: 14257

I'm not really sure if i understand your question correctly, but this function should be adding the classes to a container if it has a certain number of children matching the childSelector. And it should be performant too.

// add  some lists to the dom
function setUp(lists, elementsPerList) {
  var fragment = document.createDocumentFragment();
  for(var i = 0; i < lists; ++i) {
    let list = document.createElement('ul');
    list.classList.add('test-layout');
    for(var j = 0; j < elementsPerList; ++j) {
      var element = document.createElement('li');
      element.textContent = 'list item ' + i + '.' + j;
      list.appendChild(element);
    }
    fragment.appendChild(list);
  }
  document.body.appendChild(fragment);
}
setUp(200, 11);
// add a button to run the function
document.getElementById('test').addEventListener('click', function() { addClassOnRequirement('li', '.test-layout', 'test', 3) })
// relevant part
function addClassOnRequirement(childSelector, containerSelector, klass, cols) {
    if(cols !== 2 && cols !== 3) return;
    var containers  = document.querySelectorAll(containerSelector);

    for(var i = 0; i < containers.length; ++i) {   
      var container = containers[i];
      var children = container.querySelectorAll(childSelector);
      if(children.length % cols !== 0) {
        container.classList.add(klass);
      }
    }
}
.test {
  background: red;
  opacity: .5;
  width: 50%;
}
<button id="test">test</button>

Upvotes: 1

Related Questions