7

I've been working with scripts making use of setInterval(fn,delay) function in my application and after reading about how setTimeout and JS work I encounter some weird results so I made a test: Here is the jsfiddle https://jsfiddle.net/jyq46uu1/2/

And the code as suggested:

var limit        = 1000000000;
var intervals    = 0;
var totalTime    = new Date();
var startTime    = new Date();

var uid = setInterval(
    function () {
        // final lap?
        if (intervals == 9) clearInterval(uid);

        for (i = 0; i < limit; i += 1) {
            // just working the CPU
        }
        // reduce the iterations
        limit = limit / 10;   
        intervals += 1;        

        console.log('Interval ' + intervals +' Time elapsed : ' + (new Date() - startTime));
        // reset the time
        startTime    = new Date();
    }, 250, 9);

Ok, from what I've red from http://ejohn.org/blog/how-javascript-timers-work/ Javascript make the timer calls for the function in setInterval even if the "thread is blocked", so if the function is still executing the call is just queued and so on and so on ... in my notebook that code produces this:

"Interval 1 Time elapsed    : 4264" 
"Interval 2 Time elapsed    : 477" 
"Interval 3 Time elapsed    : 91" 
"Interval 4 Time elapsed    : 170" 
"Interval 5 Time elapsed    : 246" 
"Interval 6 Time elapsed    : 242" 
"Interval 7 Time elapsed    : 248" 
"Interval 8 Time elapsed    : 248" 
"Interval 9 Time elapsed    : 248"

Ok, if what I've red is true, by the time the first interval finished, ALL functions calls were in the queue ... in my script I'm reducing the work for every execution so every call should take fewer seconds than the previous one, BUT no matter how much iterations I set, the elapsed time always pick up the Interval pace after the 4th run. Maybe I got it wrong but if by the time 4264 all functions are already in the queue and are suppose to run immediately, they should show less time, right? ... if the 3th iteration displays 91 and the others are just behind they should take 91 or less. But this is not the case.

If you understand what is happening please explain it to me because I think I'm missing something.

Alexander O'Mara
  • 58,688
  • 18
  • 163
  • 171
Gabriel Matusevich
  • 3,835
  • 10
  • 39
  • 58

3 Answers3

1

I think the first time is not counting from the initial interval in the queue, but from the point where you set startTime.

Then the first timer is counting initialization time, environment creation, variables and timers allocation.

Try this modification:

var limit        = 1000000000;
var intervals    = 0;
var totalTime    = new Date();
var startTime    = false;

var uid = setInterval(
    function () {
        if (!startTime) startTime = new Date();
        // final lap?
        if (intervals == 9) clearInterval(uid);

        for (i = 0; i < limit; i += 1) {
            // just working the CPU
        }
        // reduce the iterations
        limit = limit / 10;   
        intervals += 1;        

        console.log('Interval ' + intervals +' Time elapsed : ' + (new Date() - startTime));
        // reset the time
        startTime    = new Date();
    }, 250, 9);

Also, the first time takes longer probably because the function is being interpreted, then the subsequent times is being executed "compiled"/optimized by the Javascript JIT ( see https://en.wikipedia.org/wiki/Just-in-time_compilation ). Check out this code to see the proof

var limit        = 1000000000;
var intervals    = 0;
var totalTime    = new Date();
var startTime    = new Date();

var uid = setInterval(
    function () {
        startTime = new Date();
        // final lap?
        if (intervals == 9) clearInterval(uid);

        for (i = 0; i < limit; i += 1) {
            // just working the CPU
        }
        // reduce the iterations
        limit = limit / 10;   
        intervals += 1;        

        console.log('Interval ' + intervals +' Time elapsed : ' + (new Date() - startTime));
        // reset the time
        startTime    = new Date();
    }, 250, 9);

the output:

Interval 1 Time elapsed : 3249
Interval 2 Time elapsed : 299
Interval 3 Time elapsed : 31
Interval 4 Time elapsed : 5
Interval 5 Time elapsed : 0
Interval 6 Time elapsed : 0
Interval 7 Time elapsed : 0
Interval 8 Time elapsed : 0
Interval 9 Time elapsed : 0
Interval 10 Time elapsed : 0

setInterval is not good measuring the time in which it should queue the next execution. I think this has to do with sleep()ing. It is not reliable if a process is taking the cpu and hanging it (like the for you do).

setInterval guarantees only this:

  • Execution number 1 is not going to happen in less than 250ms.
  • Execution number 2 is not going to happen in less than 2*250ms ahead.
  • Execution number 3 is not going to happen in less than 3*250ms ahead.
  • ...

setInterval does not guarantee that some execution is going to happen before a determined time in the future. That depends on the current CPU usage.

The queuing and launching of queued functions depends also on current CPU usage.

Extra Common Advice If you need to execute a function periodically, I recommend this approach that guarantees a delay always greather than 250ms between executions

var t = false;
var fun = function() {
    console.log("run");
    t = setTimeout(fun, 250);
}
fun();
jperelli
  • 6,988
  • 5
  • 50
  • 85
0

I am not sure I am right on this and it is on what I know of "Javascript".

Javascript is based on event based triggering and there is "no queue and wait". It will be just go concurrently (something like threading).

I guess this will make sense as how fast it interpret and taking up the next.

Eric T
  • 1,026
  • 3
  • 20
  • 42
  • not at all @Alexander, please read here. http://stackoverflow.com/questions/2734025/is-javascript-guaranteed-to-be-single-threaded – Eric T Jul 08 '15 at 05:03
  • 1
    Read the highest-rated comments on that answer. Such behavior doesn't make JavaScript multi-threaded. That's the behavior of the host when the script calls the environments API's, which can call more of your code before returning to the code that called the API. No two sections of your code will ever execute at the same time (without a worker that is). – Alexander O'Mara Jul 08 '15 at 05:13
  • pretty arguable, when you're able to execute/calls multiple scripts concurrently. It wasn't called to be multi threading? – Eric T Jul 08 '15 at 05:35
0

Well I have some points to talk about, see the results first.

Results Image

The "new" code:

var limit        = 1000000000;
var intervals    = 0;
var totalTime    = new Date();

top.uid = setInterval(
    function () {
        startTime    = new Date();
        // final lap?
        if (intervals == 9) clearInterval(top.uid);

        for (i = 0; i < limit; i += 1) {
            // just working the CPU
        }
        // reduce the iterations
        limit = limit / 10;
        intervals += 1;

        console.log('Interval ' + intervals +' Time elapsed : ' + (new Date() - startTime));
        // reset the time
    }, 1);

Note that I remove the variable startTime from line 4 and pass it to the beginning of the function, so, the computed time is the same to all calls. I changed the TIMER form 250ms to 1ms, so you don't have to calculate -250ms from every result.

The new results are pretty consistent and show the time spend to calculate are very aceptable and coherent now.

Hope I helped to clear it up.

ekad
  • 14,436
  • 26
  • 44
  • 46