简体   繁体   中英

Improve performance in js `for` loop

So I'm looking for some advice on the best method for toggling the class (set of three) of an element in a loop ending at 360 iterations. I'm trying to avoid nested loops, and ensure good performance.

What I have:

// jQuery flavour js
// vars
var framesCount = '360'; // total frames
var framesInterval = '5000'; // interval
var statesCount = 3; // number of states
var statesCountSplit = framesInterval/statesCount;
var $scene = $('#scene');
var $counter = $scene.find('.counter');    

// An early brain dump
for (f = 1; f < framesCount; f += 1) {
  $counter.text(f);
  for (i = 1; i < statesCount; i += 1) {
    setTimeout(function() {
        $scene.removeClass().addClass('state-'+i);
      }, statesCountSplit);
    }
}

So you see for each of 360 frames there are three class switchouts at intervals. Although I haven't tested I'm concerned for the performance hit here once that frames value goes into the thousands (which it might).

This snippet is obviously flawed (very), please let me know what I can do to make this a) work, b) work efficiently. Thanks :-)

Some general advice:

1) Don't declare functions in a loop

Does this really need to be done in a setTimeout?

for (i = 1; i < statesCount; i += 1) {
    setTimeout(function() {
        $scene.removeClass().addClass('state-'+i);
    }, statesCountSplit);
}

2) DOM operations are expensive

Is this really necessary? This will toggle so fast that you won't notice the counter going up. I don't understand the intent here, but it seems unnecessary.

$counter.text(f);

3) Don't optimize early

In your question, you stated that you haven't profiled the code in question. Currently, there's only about 1000 iterations, which shouldn't be that bad. DOM operations aren't too bad, as long as you aren't inserting/removing elements, and you're just modifying them.

I really wouldn't worry about performance at this point. There are other micro-optimizations you could apply (like changing the for loop into a decrementing while loop to save on a compare), but you gave no indication that the performance is a problem.

Closing thoughts

If I understand the logic correctly, you're code doesn't match it. The code will currently increment .counter as fast as the processor can iterate over your loops (should only take a few milliseconds or so for everything) and each of your "class switchouts" will fire 360 times within a few milliseconds of each other.

Fix your logic errors first, then worry about optimization if it becomes a problem.

Don't use a for loop for this. This will generate lots of setTimeout events which is known to slow browsers down. Use a single setTimeout instead:

function animate(framesCount, statesCount) {
     $scene.removeClass().addClass('state-'+statesCount);
     if (framesCount) {
         setTimeout(
             function(){
                 animate(framesCount-1,(statesCount%3)+1);
             },
             statesCountSplit
         );
     }
}

animate(360*3,1);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM