-1

I have a json which contains list of serialized objects. And I want to walk this json and show messages from it one message per 2 seconds and then stop. I did it this way:

$.ajax({
      type: 'GET',
      url: basename+'/getUnprocessedList/123',
      dataType: 'jsonp',
      success: function (data) {
        for(var i=0, keys=Object.keys(data), l=keys.length; i<l; i++) {
            console.log('hit '+i);
            setInterval(processMessage(data[i]),2000);
             }}
});

But nothing working there, setInterval just ignored, all messages displayed at once, like no any timeout. I tried $.each, setTimeout, nothing works. What's wrong there?

Mihai Alexandru-Ionut
  • 47,092
  • 13
  • 101
  • 128
avalon
  • 2,231
  • 3
  • 24
  • 49
  • `processMessage(data[i])` immediately calls the function. – nicovank Dec 07 '16 at 21:43
  • See http://stackoverflow.com/questions/32770286/javascript-settimeout-doesnt-seem-to-work-like-i-expect regarding how you're calling `setInterval()`, and http://stackoverflow.com/questions/1451009/javascript-infamous-loop-issue regarding the use of the variable `i`. – Barmar Dec 07 '16 at 21:55

3 Answers3

2

Too many errors to count in this one line:

        setInterval(processMessage(data[i]),2000);

Correct version:

setTimeout((function(i){return function(){processMessage(data[i])}})(i), 2000*i);

Your problems:

  • You're invoking the function immediately -- wrap it in a function
  • i will go out of scope by the end -- wrap your function in a closure
  • Use setTimeout with staggered intervals instead, to make it easier to keep track of i
Scimonster
  • 32,893
  • 9
  • 77
  • 89
  • Thanks, just checked - it writes hit+i 5 times, then waits, then all 5 messages at once. No consequent messaging so far :( – avalon Dec 07 '16 at 21:52
  • @avalon You included the `2000*i`? – Scimonster Dec 07 '16 at 21:53
  • yes, sorry, now I realized it works. Thank you that much! setTimeout((function(i){return function(){processMessage(data[i])}})(i), 2000*i); - this works :))) wohaaaa!! – avalon Dec 07 '16 at 21:54
  • @avalon If that's too many anonymous functions for your liking, i posted an alternate answer that may be simpler. – Scimonster Dec 07 '16 at 21:57
1

Instead of using a for loop, you can do your own looping in the setInterval.

success: function (data) {
    var i=0, keys=Object.keys(data), l=keys.length;
    var t=setInterval(function(){
        processMessage(data[i]);
        if(++i==l){clearInterval(t)}
    }, 2000);
}

This will repeat every 2 seconds, and stop when it reaches the end.

Scimonster
  • 32,893
  • 9
  • 77
  • 89
0

It's because you're invoking the function immediately in the setInterval call - to pass a function, you omit the () - but since you need a param - use an anonymous function:

setInterval(function() { processMessage(data[i]) },2000);

And you'll probably run into the issue of i being wrong now (because i will be the last iteration at the time of running, so wrap that in an IIFE)

(function(i) {
    setInterval(function() { processMessage(data[i]) },2000);
})(i)

OR - if you can, use let in your for loop:

for(let i=0, keys=Object.keys(data), l=keys.length; i<l; i++) {
    setInterval(function() { processMessage(data[i]) },2000);
} 
tymeJV
  • 103,943
  • 14
  • 161
  • 157