最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

jquery - Javascript loop through array infinitely not working - Stack Overflow

programmeradmin1浏览0评论

I have this Javascript code.

var headlineStore = [
    function headline1(){
       //irrelevant code
    },
    function headline2(){
       //irrelevant code
    },
    function headline4(){
       //irrelevant code
    },
    function headline4(){
       //irrelevant code
    },
    function headline5(){
       //irrelevant code
    }
]


 for(var i = 0; i < headlineStore.length; i++){  //for loop to loop through array named headlineStore

     if(i == 4) //if condition to reset the counter once it reaches 5
     {
         i = 0;
     }

     (function(i){
         setTimeout(function(){
             headlineStore[i]();
         }, 5000  * i);
     }(i)); //Will load each function in the array with timeout increments 
 }  

What I have here is a for loop that loops through an array filled with functions. On every iteration a function from the array is retrieved and executed with time intervals.

What I want is that after the last function is retrieved it loops through the array again starting with the first function and will do this infinitely.

What I tried is resetting the counter when it reaches 4 but it goes out of the loop and continue executing, then for some reason the page bee unresponsive.

I have this Javascript code.

var headlineStore = [
    function headline1(){
       //irrelevant code
    },
    function headline2(){
       //irrelevant code
    },
    function headline4(){
       //irrelevant code
    },
    function headline4(){
       //irrelevant code
    },
    function headline5(){
       //irrelevant code
    }
]


 for(var i = 0; i < headlineStore.length; i++){  //for loop to loop through array named headlineStore

     if(i == 4) //if condition to reset the counter once it reaches 5
     {
         i = 0;
     }

     (function(i){
         setTimeout(function(){
             headlineStore[i]();
         }, 5000  * i);
     }(i)); //Will load each function in the array with timeout increments 
 }  

What I have here is a for loop that loops through an array filled with functions. On every iteration a function from the array is retrieved and executed with time intervals.

What I want is that after the last function is retrieved it loops through the array again starting with the first function and will do this infinitely.

What I tried is resetting the counter when it reaches 4 but it goes out of the loop and continue executing, then for some reason the page bee unresponsive.

Share Improve this question edited Apr 14, 2016 at 18:25 user3703944 asked Apr 14, 2016 at 18:18 user3703944user3703944 713 silver badges9 bronze badges 8
  • 1 You are doing that wrong.. try to change the logic that you have to use setInterval, instead of for – Hugo S. Mendes Commented Apr 14, 2016 at 18:22
  • I can hardly even think about this code without my head asploding. – Dave Newton Commented Apr 14, 2016 at 18:23
  • 1 This approach is going to create millions of timers very quickly and exhaust available resources. I doubt that's a requirement. – Tibrogargan Commented Apr 14, 2016 at 18:25
  • This is an infinite loop. It will crash the page or browser depending on OS and browser types. – Travis J Commented Apr 14, 2016 at 18:27
  • 1 What you have here is an XY problem. You created an infinite loop to do some work, but have not shown what work needs an infinite loop to be acplished. – Travis J Commented Apr 14, 2016 at 18:28
 |  Show 3 more ments

5 Answers 5

Reset to default 4

You need to wait until the last one executes before setting the next timeout:

var headlineStore = [
    function headline1(){
       document.write('1');
    },
    function headline2(){
       document.write('2');
    },
    function headline3(){
       document.write('3');
    },
    function headline4(){
       document.write('4');
    },
    function headline5(){
       document.write('5');
    }
]

function nextHeadline(index) {
  headlineStore[index]();
  window.setTimeout( 
    nextHeadline.bind(undefined, (index + 1) % headlineStore.length), 1000 );  
}

nextHeadline(0);

I think this is more along the lines of what you need (call 1 function every 5 seconds). Support for this use of setTimeout depends on the browser

var timeoutHandle = undefined;

headlineStore =
[ function1
, function2
, function3
  ...
];

function showHeadline(idx) {
    headlineStore[idx](idx);
    timeoutHandle = setTimeout(showHeadline, 5000, (idx+1)%headlineStore.length);
}

showHeadline(0);

You can utilize .queue() , .promise()

var headlineStore = [
  function headline1(next) {
    //irrelevant code
    console.log("headline1");
    setTimeout(next, 5000);
  },
  function headline2(next) {
    //irrelevant code
    console.log("headline2");
    setTimeout(next, 5000);
  },
  function headline3(next) {
    //irrelevant code
    console.log("headline3");
    setTimeout(next, 5000);
  },
  function headline4(next) {
    //irrelevant code
    console.log("headline4");
    setTimeout(next, 5000);
  },
  function headline5(next) {
    //irrelevant code
    console.log("headline5");
    setTimeout(next, 5000);
  }
];

(function cycle() {
  return $({}).queue("headlines", $.map(headlineStore, function(headline, i) {
      return headline
    })).dequeue("headlines")
    .promise("headlines")
    .then(cycle) // loop infinitely
}());
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js">
</script>

I don't know what you are trying to achieve, but I will try explaining why your code is not working.

JS runs on single thread and any function you put in setTimeout or setInterval is queued in the event queue. Functions from this event queue are run only when the main thead on which your JS code was running is free.

To explain what I said, follow this code

(function() {

    // A function queued to be called after 200 ms but it gets called 
    // only when the main thread has finished executing this piece of 
    // code inside the IIFE 
    setTimeout(function() { 
        console.log('Intended to be called after 200 ms delay, however called after the blocking pleted');
    }, 200);

    // However the main thead is intentionally blocked here for 5 sec
    // so the queued call can only happen post this IIFE has finished 
    // execution.

    console.log('About to start 5 sec blocking');   
    var now = +new Date;
    while(+new Date - now < 5e3); // simulating 5 sec blocking
    console.log('blocking plete.');

})();

To better understand the queue and related stuff, I would remend watching What the heck is Event Loop

Now, ming back to your question, you inadvertantly created an infinite loop when you set i = 0 in the if(i == 4) block. So, ultimately, you are queuing the functions in the event queue, but not freeing the main thread. Hence the event queue never get a chance to execute.

function first() {
    console.log('hello from first function');
}

function second() {
    console.log('hello from second function');
}

function third() {
    console.log('hello from third function');
}

function fourth() {
    console.log('hello from fourth function');
}

function fifth() {
    console.log('hello from fifth function');
}

var array = [first, second, third, fourth, fifth];

for (var i = 0, len = array.length; i < len; i++) {

    if (i == 4) { i = 0;} // this causes infinite loop

    console.log('I became an infinite loop');

    // functions are added to the queue, but the main thread is stuck in an infinite loop 
    // hence cannot execute these timeouts
    (function(i) {
        setTimeout(function() {
            array[i]();
        }, 1e2*i);
    })(i);
}

Therefore, you need a way to call an array of functions on and on. This seems to me a use case for recursion. I hope that you could achieve easily.

The problem is that this function will loop forever before the first timeout ever fires the first array function. You need to increment the loop within the timeout function. and make it wait.

Try this:

var headlineStore = [
    function headline1(){
       //irrelevant code
    },
    function headline2(){
       //irrelevant code
    },
    function headline3(){
       //irrelevant code
    },
    function headline4(){
       //irrelevant code
    },
    function headline5(){
       //irrelevant code
    }
]


var i = 0;

function loopForever(){
    setTimeout(function(){
        headlineStore[i]();
        i++;
        if(i == 5){
            i = 0;
        }
        loopForever();
    }, 5000  * (i + 1)); // I added the +1, else your first function fires immediately.  seemed like you didn't want that.
}
发布评论

评论列表(0)

  1. 暂无评论