12

Here's the simplest code for reproducing I could think of:

ms = 30; // 1000 ?
num = 1;
function test()
{
    num+=ms;
    document.getElementById('Submit').value = num; // Using native Javascript on purpose
    if (num < 4000)
        window.setTimeout(test, ms);
}
test()

I set the ms (milliseconds between iterations) to 30, ran the script and moved to different tab on the browser.

Then I wait for about 10 seconds (the script should finish within 4 seconds) and came back to the tab.

If I used Firefox I saw that the script has not finished, and the numbers are still running (resuming from where I left them, I guess).

Which is annoying enough,

But if I changed ms to 1000 and repeat the above steps, when I come back to the tab I saw the script has indeed already finished.

(The script should still take 4 seconds to finish).

Namely, sometimes Firefox runs window.setTimeout even if the window is out of focus, and sometimes it doesn't. Possibly depending on the duration

On the other hand, this is not happening with Internet Explorer.

It keeps running the script even if the tab is not focused. No matter how I set the ms.

  • Is that due to some performance considerations of Firefox?

  • What exactly is happening?

  • How come such a basic thing is in consistent between browsers, nowadays?

OR, am I working wrong? Is it a weird way for coding?

I'm just trying repeatedly change the DOM, in a delayed fashion, without using setInterval (because I'm changing the interval it self on the go).

  • And most important, how should I regard this?

I can't assume my user won't leave the tab.

I want to allow my user to leave the page for as mush as one might like.

If one leaves and come back after half an hour, he/she will see irrelevant animations on the page, still running.

Some of these animations are seen by all the users connecting to the page.

There is no need they will be synchronized in resolution of milliseconds, but I can't start them only when the user put the tab/window in focus.

I'm using Firefox 25.0.1, and IE 11. (Windows 7)

Letterman
  • 4,076
  • 5
  • 29
  • 41
  • 1
    THe minimum interval of `setTimout` and `setInterval` is 1000ms on [chrome](https://github.com/adobe/chromium/blob/master/webkit/glue/webkit_constants.h) and [firefox](http://dxr.mozilla.org/mozilla-central/search?tree=mozilla-central&q=DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE&redirect=true) for inactive tabs – Moritz Roessler Dec 19 '13 at 12:10
  • @C5H8NNaO4 I could not find an answer there for "how should I regard this". Can I force animations the run while window not in focus? – Letterman Dec 19 '13 at 12:11

3 Answers3

12

Most modern browsers (especially on mobile devices) suspend execution of scripts in tabs that are out of focus to save CPU cycles (for instance, this is why requestAnimationFrame was brought to life). In the case of timeouts, shorter intervals are actually changed to a different / higher value as the browser vendor sees fit.

What you can do to overcome this (if you really must know the interval between successive executions) is to set a timestamp when the timeout is activated, and compare it with the timestamp when the timeout handler is actually executed. Note that when you're animating it's best to calculate properties of the animated Objects by taking other application variables into account, rather than rely on the amount of calls a particular handler has had.

You could also attach listeners to the window for "(un)focus" Events to know when the user has "come back" to your application. In this event handler you can verify whether a timeout was pending and execute its callback manually, if you must do so.

Igor Zinken
  • 884
  • 5
  • 19
3

see the difference: http://jsfiddle.net/qN6eB/

ms = 30; // 1000 ?
num = 1;
start = new Date();

function test()
{
    num+=ms;
    document.getElementById('Submit').value = num;
    if (num < 4000)
        window.setTimeout(test, ms);
    else
        document.getElementById('Time').value = new Date() - start;
}

test()



ms2 = 30; // 1000 ?
num2 = 1;
start2 = new Date();
dueTo = new Date(+new Date()+4000);

function test2()
{
    num2+=ms2;
    document.getElementById('Submit2').value = num2;
    if (new Date() < dueTo)
        window.setTimeout(test2, ms2);
    else 
        document.getElementById('Time2').value = new Date() - start2;
}
test2()
Endless
  • 34,080
  • 13
  • 108
  • 131
-1

setTimeout is not precise for timing. Because the timer doesn't interrupt the process, I'll wait for idle time. I don't know how the browsers are managing it, but an inactive tab probably has a lower priority.

I can think about two solutions : - Try setInterval (I'm not sure if this will solve your problem or not) - Instead of incrementing a variable, use a Date object, containing the time at the beginning, and compare it with the current time when the function is executed.

var beginTime = (new Date()).getTime();
var intervalId = setInterval(function() {
    var timePassed = (new Date()).getTime() - beginTime;
    document.getElementById('Submit').value = timePassed;
    if(timePassed >= 4000) {
        clearInterval(intervalId);
    }
}, 30);
Sebastien C.
  • 4,649
  • 1
  • 21
  • 32