3

I'm a JavaScript newbie and I'm trying to achieve concurrent actions with setInterval and setTimeout.

What I'd like to achieve, what actually happens and what I expected to happen is best explained with the following code.

var myVar = setInterval(function() {
  myTimer()
}, 1000);

function myTimer() {
  var d = new Date();
  var t = d.toLocaleTimeString();
  document.getElementById("demo").innerHTML = t;
}

for (var i = 0; i < 100; i++) {
  setTimeout(function() {
    console.log("log " + i);
  }, 3000);
}
<p>A script on this page starts this clock:</p>
<p id="demo"></p>

My expectation for the leading setInterval, is that the function myTimer is executed every second, independent of what happens afterwards. Except of course if the site is closed or clearTimeout is called on the myVar.

I can not verify if this action really happens independently and in an ongoing manner.

The following for loop, is there to simulate further code, to see if the myTimer function would be executed independently.

I expected the loop to start with i=0, then wait for three seconds, log log 0 to the console, then continue with i=1 and so on.

Instead it appears that the timeout is started and in the meantime i has reached the end of the for loop and is therefore 100.

How do I get the for loop to wait with the iteration for the setTimeout?

And is the setInterval really executed every second, independent of the following code? E.g. if the following code had actions that take some processing/time, would the clock update anyways, during the processing?

Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
MikeDyson
  • 59
  • 1
  • 8
  • you might have a look here: http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example – Nina Scholz Mar 13 '17 at 12:04
  • I'll go over that, thanks. If I understand it correctly it concerns with the iteration and the `i` variable. Do you have a comment about my questions on `setInterval` and `setTimeout`? – MikeDyson Mar 13 '17 at 12:13
  • 1
    You might also find this useful [Is there a sleep function in JavaScript?] (http://stackoverflow.com/questions/1141302/is-there-a-sleep-function-in-javascript). It looks like you are trying to suspend execution using the settimeout - but that won't work because settimeout doesn't block execution, it defers it by putting the callback on the event queue to be executed at a later time - the current turn then immediately continues. – Bob Gear Mar 13 '17 at 12:13
  • Thanks @BobGear, that explains my issue with `setTimeout`. Is `setInterval` *asynchronous* as well, so that it runs independently of the rest of the code? – MikeDyson Mar 13 '17 at 12:15
  • My under standing is that it is - every time the interval fires, the callback executes *and* another item is put on the event loop ready for it to be fired the next time the interval expires. – Bob Gear Mar 13 '17 at 12:23

2 Answers2

3

You could change the timeout time with the factor of i and use a closure over i to get the right value.

function myTimer() {
    var d = new Date();
    var t = d.toLocaleTimeString();
    document.getElementById("demo").innerHTML = t;
}

var i,
    myVar = setInterval(myTimer, 1000);

for (i = 0; i < 100; i++) {
    setTimeout(function (i) {
        return function() {
            console.log("log " + i);
        };
    }(i), 3000 * i);
}
<p>A script on this page starts this clock:</p>
<p id="demo"></p>

A version with calling timeout after timeout.

function myTimer() {
    var d = new Date();
    var t = d.toLocaleTimeString();
    document.getElementById("demo").innerHTML = t;
}

function next() {
    i++;
    console.log("log " + i);
    if (i < 300) {
        setTimeout(next, 3000);
    }
}

var i = 0,
    myVar = setInterval(myTimer, 1000);

setTimeout(next, 3000);
<p>A script on this page starts this clock:</p>
<p id="demo"></p>
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • 1
    This works exactly like I intended/expected my code to, but I can't really wrap my head around how this works. So you run a function, in `setTimeout`, which `return`s a function, which runs the `console.log`? and you multiply the timeout time by 3000 ms for every `i`? Sorry - I'm lost. – MikeDyson Mar 13 '17 at 12:37
  • right. the closure over `i` keeps the value and the multiplication with i delays the call of the returned function. – Nina Scholz Mar 13 '17 at 12:40
  • Does that mean that the for loop runs immediately through all 100 `i`s and each log is actually kept *somewhere* on hold, until the 3 seconds * `i` have expired, then it's executed? – MikeDyson Mar 13 '17 at 12:49
  • right. for a different approach, you could chain the interval, where each function sets an interval in 3000 ms for the next. – Nina Scholz Mar 13 '17 at 12:53
  • This is so confusing, coming from other languages. Thank you for your help – MikeDyson Mar 13 '17 at 13:00
1

About your setInterval question, yes. It will run every second (not being millisecond scrupulous). let's say you just set your setInterval, and then run an action that takes half a second to run. The interval will count that half second and run after another half second. Hard code will not delay the clock, BUT, if you are running code just in the moment that the interval should fire, it will wait for that code to end, as JavaScript is single threaded. This means that if right after setting your interval you run code that lasts more than 1 second, the interval callback will be ran after it, so it will not be fired in 1 second. By the way, subsequent interval calls will be called not after this interval, but after the interval was set. Check this fiddle (F12): https://jsfiddle.net/0gggmemu/4/

You see that the first interval is called when the code ends, but subsequent intervals are called counting when the interval was set (check milliseconds, how they fit the first log instead of the start one). Note that the intervals are not stacked. If it should have called 10 intervals, it will only call one and wait for the next. If time precision is important for you, then you should save a reference at startup and check the difference in each interval.

About concurrency, the same as when you call setInterval, when you call setTimeout the code will continue its execution, creating a hundred of timeouts at the same time. If you want code to hang just check my fiddle. By the way, if your worry is about setTimeout locking setInterval, don't worry, as the code will not be blocked. You only have to semi-worry if you have code that gets stuck somewhere, but in a callback-driven application is kinda difficult to achieve this.

Jorge Fuentes González
  • 11,568
  • 4
  • 44
  • 64