views:

56

answers:

4

I am trying to set an interval when some code runs but only need to do it based on the number of elements there are. Here's a quick example:

5 total elements

Run code once every 20 seconds for each element that is found.

Can someone please give me a basic example how to do this using plain JavaScript? Everything I have tried just executes all of the code at once instead of doing one element at a time.

A: 

You have to define a function, and inside the function it needs to set a timeout on itself. Like this:

var els = [1, 2, 3, 4, 5];

var process_els = function(el_index) {
  var el = els[el_index];

  // do stuff to el here
  console.log(el);
  // do stuff to el above

  if (el_index + 1 < els.length) {
    setTimeout('process_els('+(el_index + 1)+');', 20000);
  }
}
process_els(0);
Ben Lee
You never should pass a string in a setInteval or setTimeout, it's an expensive and bad practice for the implicit eval() it needs.
Fabrizio Calderan
@Fabrizio Calderan, the performance hit here for eval() is for all practical purposes non-existent -- it's not like this method is running 100,000 times. Optimizing here should be for code readability and maintainability, not cpu cycles. I hope the downvote this go wasn't from you for this, because really this is the right solution to the problem.
Ben Lee
Even if you want to avoid eval() for some reason, it is easy to refactor it out. Put a "var process_els = null;" above the actual method declaration, then instead of 'process_els('+el_index+1)+');', put function() { process_els(el_index + 1); }
Ben Lee
@ben, is anyway a bad practice and should absolutely be avoid.
Fabrizio Calderan
@Ben Lee, I dropped your code into my method and I keep getting "process_els is not defined". Any ideas what needs to be changed to the function call in the setTimeout so it will find it? I've tried adding "this." to it and also removed the 's, but it never finds the process_els function?
jttm
I just tested it and it's working for me. Are you sure there isn't a typo? You definitely have "var process_els = function() {...}"? If you're sure it's not a typo, what web browser are you using?
Ben Lee
@jttm, also try @Fabrizio Calderan's solution above. It is cleaner than my example.
Ben Lee
+2  A: 

let's suppose you're talking about elements of an array or a DOM collection

(function() {
   var arr = [...],
       len = arr.length;


   (function doProcess() {
       if (len--) {
           /* do something with arr[len] */
           setTimeout(doProcess, 20000);
       }
   })();    
})();

Edit: if you cannot reverse the array for any reason just use next version

(function() {
   var arr = [...],
       len = arr.length;


   (function doProcess(i) {
       if (i) {
            console.log(len - i);
           /* do something with arr[len - i] */
           setTimeout(function() { doProcess(--i); }, 20000);
       }
   })(len);    
})();
Fabrizio Calderan
This evaluates the items in reverse order.
Ben Lee
no panic, just reverse the array if you need to compute the array in its exact order :)
Fabrizio Calderan
That's fine as long as you don't need to maintain array order for later.
Ben Lee
@ben: in that case He will make a copy of the array. This is only a snippet for what he asked, nothing more.
Fabrizio Calderan
Yes, I know. Just pointing out the caveat to prevent confusion.
Ben Lee
A: 

Here's some code I did for animating images using jQuery:

var enter = 500;
var show = 4000;
var exit = 300;
var direction1 = "right"; 
var direction2 = "left";
var logo = document.getElementById('Box1').getElementsByTagName('img');
var Num = $('#Box1 img').length;
var time_each = (enter+show+exit);
function startBox1(){
for(x=0;x<=Num-1;x++){
Box1(x);
}
}  
function Box1(x){
var buffer = time_each*x;
$(logo[x]).delay(buffer).show("slide", { direction: direction1 }, enter).delay(show).hide("slide", { direction: direction2 }, exit);
}
$(function(){
startBox1();
setInterval("startBox1()",(time_each)*Num);
});

The trick was to set a buffer which equaled the time it took for each animation by the index of the current animation. The FOR loop runs each code immediately; the .delay() action and the buffer variable makes it appear as if each animation was happening one after the other. Then setInterval() recalls the FOR loop after every animation is complete. It restarts the process continuously.

bozdoz