-1

I want to print some numbers using a for loop at an interval of two seconds each. The outer loop is needed in all these snippets because I need it for some other manipulation, so please don't say that there is no need for two loops.

The following code snippet waits for about 2 seconds and then prints 61 fifty times at once.

for(var i=0;i<1;i++) { 
    for(var j=1;j<51;j++) {
        window.setInterval(function(){
            console.log(10*i + j);
        }, 2000);
    }  
}

I thought it will print 1 -- wait 2 seconds -- print 2 -- wait 2 seconds -- and so on. I thought that I am asking the browser to stop for two seconds after each iteration of the inner loop and then print the numbers. Also, I thought that the printing would stop after one iteration of the outer loop but it does not and the console keeps printing 61. One more thing, why is it printing 61?

Edit: After comments from zerkms, I now have the following code:

for(var i=0;i<1;i++) { 
    for(var j=1;j<51;j++) {
        window.setTimeout(function(){
            console.log(10*i + j);
        }, 2000*j);
    }  
}

It prints out 50 lines at an interval of 2 seconds but it keeps printing 61 every single time. How can I print all the numbers?

halfer
  • 19,824
  • 17
  • 99
  • 186
SanJeet Singh
  • 1,291
  • 2
  • 15
  • 28
  • Because you're scheduling to run them all after `2000ms`. "How can I do that?" --- just schedule every next number to be output after a longer interval. – zerkms Aug 15 '16 at 02:45
  • I don't know how to do that. I thought the first version of the loop was supposed to do that and why is the first version printing 61. – SanJeet Singh Aug 15 '16 at 02:49
  • Well, the first number should be output after 2000ms, the second after 4000ms, etc. – zerkms Aug 15 '16 at 02:50
  • Yeah, I have already tried two methods to do so. Apparently none of them work. So, I turned to stackoverflow to know the reason. – SanJeet Singh Aug 15 '16 at 02:51
  • Wait, I think I understand now. Edit : No I don't. I tried adding 2000*j but it did not work. – SanJeet Singh Aug 15 '16 at 02:52
  • "but it did not work" --- what does it mean? Sorry, cannot read your mind. – zerkms Aug 15 '16 at 03:05
  • 1
    The problem from the actual code solves the same way the problem from a made up code: just increase the interval (but using `setTimeout`). After you're able to do that - solve the problem of captured variables in a closure. – zerkms Aug 15 '16 at 03:10
  • Let me try that :) – SanJeet Singh Aug 15 '16 at 03:13
  • I replaced setInterval with setTimeout. The time interval is now correct but the console keeps printing 61 instead of different numbers. I am updating my question to show the new code. – SanJeet Singh Aug 15 '16 at 03:26
  • 1
    And now check http://stackoverflow.com/q/750486/251311 – zerkms Aug 15 '16 at 03:29
  • Thank you very much zerkms :). I can now print the numbers at different intervals. Just one question. Do I have to write a separate function whenever I need to print out values from a loop using closures? – SanJeet Singh Aug 15 '16 at 03:44
  • 1
    Not necessary, see the second and third answers there http://stackoverflow.com/a/750495/251311 – zerkms Aug 15 '16 at 03:55

1 Answers1

1

I thought that I am asking the browser to stop for two seconds after each iteration of the inner loop and then print the numbers.

You're simply misunderstanding the nature of setInterval. When you call setInterval, you are saying:

Browser, I am going to give you a function, and I want you to run that function every two seconds until I tell you to stop.

One right way to do what you're hoping to do is this:

var i = 0;
var j = 1;
var interval = window.setInterval(function(){
    console.log(i, j);
    j++;
    if(j > 50) {
        j = 0;
        i++;
        if(i > 4) {
            window.clearInterval(interval);
        }
    }
}, 2000);

You'll notice you don't need any loops because setInterval is already going to repeat your function for you. Without the loop, you need to move your incrementing logic (i = 0, i++, etc.) into normal statements. Then, once you want to stop, you have to tell the browser to stop via clearInterval.

This is hard to follow, though, so depending on what you're actually trying to accomplish it's likely that there's a better way. For example, if you're trying to iterate across a couple of arrays, cross-join fashion, you could flatten your arrays out first, removing the need for one of your iterators. Or you could use a library like RxJS to zip the values you want with an interval timer.

var everyTwoSeconds = Rx.Observable.interval(2000);
var firstSetOfThings = Rx.Observable.from(['one', 'two', 'three']);
var secondSetOfThings = Rx.Observable.range(1, 50);
var allTheThings = firstSetOfThings.flatMap(secondSetOfThings, function(x, y) {
    return "first: " + x + ", second: " + y;
});
everyTwoSeconds.zip(allTheThings, function(i, thing) { console.log(thing); });
StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
  • thanks for the answer but I need both those loops as I am doing some other stuff too that requires two loops. Is there a way to print out those numbers using two loops? The `i` in outloop is supposed to go from `0` to `9`. I just simplified ti here. – SanJeet Singh Aug 15 '16 at 03:03
  • @SanJeetSingh: You don't need two loops--that's just an implementation detail. What you really need is to print two separate numbers. Just add your `var j` outside the loop where `i` is declared, and change the incrementing logic to get the behavior you're looking for. – StriplingWarrior Aug 15 '16 at 03:06
  • Actually, I wrote the simplified version of my code. I have updated the question to reflect some changes and show what I actually want to do. :) – SanJeet Singh Aug 15 '16 at 03:11
  • @SanJeetSingh: I've updated my answer with more information. The key is to understand how `setInterval` works, which involves understanding how *closures* work (if you read the segment about Variable Scoping [here](http://j2jensen.blogspot.com/2014/11/ten-things-javascriptmd.html) you should be able to understand why you're outputting the same value in your original code). Once you've got a firm grip on that, there are a number of different ways to solve the kind of problem you're facing. – StriplingWarrior Aug 15 '16 at 15:12